【LA3487】最小割-经典模型 两种方法
题意:A、B两个公司要买一些资源(他们自己买的资源不会重复),一个资源只能卖给一个公司。问最大收益。
simple input 部分:
54 1 //买到1就给54元
15 2
33 3
2 4 5//买到4、5就给2元
题解:这道题是很经典的模型题,在这里给出两个方法。
方法一 把每个询问看成一个点,然后A的询问连源点,B的询问连汇点,如果AB间的某个询问有矛盾就在它们中间连一条无限大的边,ans=sum-最小割。
// 方法一 把每个询问看成一个点,然后A的询问连源点,B的询问连汇点,如果AB间的某个
// 询问有矛盾就在它们中间连一条无限大的边,ans=sum-最小割。 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
using namespace std; const int N=,INF=(int)1e9;
int s,t,len,num;
int first[*N],dis[*N];
int A[N],B[N],p1[N],p2[N];
// bool vis[2*N];
bool vis[][];
struct node{
int x,y,d,next;
}a[*N];
queue<int> q; int minn(int x,int y){return x<y ? x:y;}
int maxx(int x,int y){return x>y ? x:y;} void ins(int x,int y,int d)
{
a[++len].x=x;a[len].y=y;a[len].d=d;
a[len].next=first[x];first[x]=len;
a[++len].x=y;a[len].y=x;a[len].d=;
a[len].next=first[y];first[y]=len;
} bool bfs(int st,int ed)
{
while(!q.empty()) q.pop();
memset(dis,-,sizeof(dis));
dis[st]=;
q.push(st);
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=first[x];i!=-;i=a[i].next)
{
int y=a[i].y;
if(dis[y]==- && a[i].d>)
{
dis[y]=dis[x]+;
q.push(y);
}
}
}
return (dis[ed]!=-);
} int dfs(int x,int ed,int flow)
{
int r=,p;
if(x==ed) return flow;
for(int i=first[x];i!=-;i=a[i].next)
{
int y=a[i].y;
if(dis[y]==dis[x]+ && a[i].d>)
{
p=minn(a[i].d,flow-r);
p=dfs(y,ed,p);
r+=p;
a[i].d-=p;
a[i^].d+=p;
}
}
if(!r) dis[x]=-;
return r;
} int dinic(int st,int ed)
{
int ans=;
while(bfs(st,ed))
{
int p;
while(p=dfs(st,ed,INF)) ans+=p;
}
return ans;
} int main()
{
int T,cas=;
scanf("%d",&T);
while(T--)
{
len=-;
memset(first,-,sizeof(first));
memset(A,,sizeof(A));
memset(B,,sizeof(B));
memset(vis,,sizeof(vis));
int n,m,sum=,mx=,num=;
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d",&p1[i]);
sum+=p1[i];
int x;num++;
while()
{
char c;
scanf("%d%c",&x,&c);
A[x]=i;
mx=maxx(mx,x);
if(c=='\n') break;
}
}
scanf("%d",&m);
s=,t=n+m+;
for(int i=;i<=m;i++)
{
scanf("%d",&p2[i]);
sum+=p2[i];num++;
int x;
while()
{
char c;
scanf("%d%c",&x,&c);
B[x]=i;
mx=maxx(mx,x);
if(c=='\n') break;
}
}
for(int i=;i<=n;i++) ins(s,i,p1[i]);
for(int i=;i<=m;i++) ins(i+n,t,p2[i]);
for(int i=;i<=mx;i++)
{
if(!A[i]||!B[i]||vis[A[i]][B[i]]) continue;
vis[A[i]][B[i]]=true;
ins(A[i],B[i]+n,INF);
}
printf("Case %d:\n",++cas);
printf("%d\n",sum-dinic(s,t));
if(T) printf("\n");
}
return ;
}
方法一
方法二:对于每个询问,新建一个点x,如果是A就源点连向这个点,流量为价钱p,然后x连向这个询问所要求买的资源c[i],流量为INF。
如果是B则反过来,连向汇点。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
using namespace std; const int N=,INF=(int)1e9;
int s,t,len,num;
int first[*N],dis[*N];
int A[N],B[N];
bool vis[][];
struct node{
int x,y,d,next;
}a[*N];
queue<int> q; int minn(int x,int y){return x<y ? x:y;}
int maxx(int x,int y){return x>y ? x:y;} void ins(int x,int y,int d)
{
a[++len].x=x;a[len].y=y;a[len].d=d;
a[len].next=first[x];first[x]=len;
a[++len].x=y;a[len].y=x;a[len].d=;
a[len].next=first[y];first[y]=len;
} bool bfs(int st,int ed)
{
while(!q.empty()) q.pop();
memset(dis,-,sizeof(dis));
dis[st]=;
q.push(st);
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=first[x];i!=-;i=a[i].next)
{
int y=a[i].y;
if(dis[y]==- && a[i].d>)
{
dis[y]=dis[x]+;
q.push(y);
}
}
}
return (dis[ed]!=-);
} int dfs(int x,int ed,int flow)
{
int r=,p;
if(x==ed) return flow;
for(int i=first[x];i!=-;i=a[i].next)
{
int y=a[i].y;
if(dis[y]==dis[x]+ && a[i].d>)
{
p=minn(a[i].d,flow-r);
p=dfs(y,ed,p);
r+=p;
a[i].d-=p;
a[i^].d+=p;
}
}
if(!r) dis[x]=-;
return r;
} int dinic(int st,int ed)
{
int ans=;
while(bfs(st,ed))
{
int p;
while(p=dfs(st,ed,INF)) ans+=p;
}
return ans;
} int main()
{
int T,cas=;
scanf("%d",&T);
while(T--)
{
len=-;
memset(first,-,sizeof(first));
memset(A,,sizeof(A));
memset(B,,sizeof(B));
memset(vis,,sizeof(vis));
int n,m,p,sum=,mx=,num=;
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d",&p);
sum+=p;
int x;num++;
ins(,num,p);
while()
{
char c;
scanf("%d%c",&x,&c);
ins(num,x+,INF);
if(c=='\n') break;
}
}
scanf("%d",&m);
s=,t=;
for(int i=;i<=m;i++)
{
scanf("%d",&p);
sum+=p;num++;
ins(num,t,p);
int x;
while()
{
char c;
scanf("%d%c",&x,&c);
ins(x+,num,INF);
if(c=='\n') break;
}
}
for(int i=;i<=n;i++) ins(s,i,p1[i]);
for(int i=;i<=m;i++) ins(i+n,t,p2[i]);
for(int i=;i<=mx;i++)
{
if(!A[i]||!B[i]||vis[A[i]][B[i]]) continue;
vis[A[i]][B[i]]=true;
ins(A[i],B[i]+n,INF);
}
printf("Case %d:\n",++cas);
printf("%d\n",sum-dinic(s,t));
if(T) printf("\n");
}
return ;
}
方法二
【LA3487】最小割-经典模型 两种方法的更多相关文章
- 【BZOJ 3232】圈地游戏 二分+SPFA判环/最小割经典模型
最小割经典模型指的是“一堆元素进行选取,对于某个元素的取舍有代价或价值,对于某些对元素,选取后会有额外代价或价值”的经典最小割模型,建立倒三角进行最小割.这个二分是显然的,一开始我也是想到了最小割的那 ...
- 清除SQLServer日志的两种方法
日志文件满而造成SQL数据库无法写入文件时,可用两种方法:一种方法:清空日志.1.打开查询分析器,输入命令DUMP TRANSACTION 数据库名 WITH NO_LOG2.再打开企业管理器--右键 ...
- WebGL中添加天空盒的两种方法
天空盒 的添加可以让模型所在的场景非常漂亮,而其原理也是非常简单的,相信看完下面代码就可以明白了. 说到天空盒的两种方法,倒不如说是两种写法,分别用了纹理加载的两个方法:loadTexture和loa ...
- [转]Delphi调用cmd的两种方法
delphi调用cmd的两种方法vars:string;begins:='cmd.exe /c '+edit1.Text+' >c:\1.txt';winexec(pchar(s),sw_hid ...
- Java学习笔记——可视化Swing中JTable控件绑定SQL数据源的两种方法
在 MyEclipse 的可视化 Swing 中,有 JTable 控件. JTable 用来显示和编辑常规二维单元表. 那么,如何将 数据库SQL中的数据绑定至JTable中呢? 在这里,提供两种方 ...
- 织梦首页、列表页调用文章body内容的两种方法
http://blog.csdn.net/langyu1021/article/details/52261411 关于首页.列表页调用文章body内容的两种方法,具体方法如下: 第一种方法: {ded ...
- 转载]PhpCms V9调用指定栏目子栏目文章的两种方法
PhpCms V9调用指定栏目子栏目文章的两种方法 第一种.直接写子栏目id ,用cat in {pc:get sql="SELECT * from v9_news where status ...
- ZBrush中设置背面遮罩的两种方法
背面遮罩是ZBrush软件实时遮罩的一种,它的出现能够解决我们在模型雕刻时的一些问题.我们在 ZBrush®中雕刻一个比较薄的物体时,经常会不经意的雕刻到背面的物体.那么遇到此类状况该如何设置ZBru ...
- [ARM-Linux开发]Linux下加载.ko驱动模块的两种方法:insmod与modprobe
假设要加载的驱动程序模块名为SHT21.ko 加载驱动模块 方法一: 进入SHT21.ko驱动模块文件所在的目录,然后直接 insmod SHT21.ko 即可 方法二: 将SHT21.ko文 ...
随机推荐
- shell -- for、while用法
#数字段形式for i in {1..10}do echo $idone #详细列出(字符且项数不多)for File in 1 2 3 4 5do echo $Filedone #对存在的 ...
- html5学得好不好,看掌握多少标签
html5学得好不好,看掌握多少标签 已回复 会员ID:wi701329 保密 62岁 时间:2016-06-28 06:52:49 html5你了解了多少?如果你还是入门阶段的话,或者还是一知半解的 ...
- 一次和别人争吵一个按钮,点击后显示导航;再点击不显示的效果,是否一定以及必须用js?
事情经过是这样的,我们组一个说话很喜欢用一定,肯定的哥们,吃午饭的时候拿了自己做的一个UI库,头部有一个按钮 点击展开,再次点击收缩,他意思说一个按钮无法记录点击状态,必须使用js.然后我看了一眼,心 ...
- Qt C++ 并发,并行,多线程编程系列1 什么是并发
什么是并发,并发往简单来说就是两个或多个独立的任务同时发生,在我们的生活中也是随处可见.如果把每个人都当作一个独立的任务,那每个人可以相互独立的生活,这就是并发. 在计算机的系统里面,并发一般有两种, ...
- bam文件测序深度统计-bamdst
最近接触的数据都是靶向测序,或者全外测序的数据.对数据的覆盖深度及靶向捕获效率的评估成为了数据质量监控中必不可少的一环. 以前都是用samtools depth 算出单碱基的深度后,用perl来进行深 ...
- 给虚拟机发送键盘按键key
使用举例:virsh send-key 11 KEY_LEFTCTRL KEY_LEFTALT KEY_DELETE作用:发送"ctrl+alt+del"给虚拟机,linux虚拟机 ...
- 【Dataset】Goodbooks-10k: 图书推荐数据
当前推荐领域一些公开的据集都是关于电影和音乐的(比如Netflix.Movielens等),没有关于图书推荐的数据.本文将要介绍的就是一份用于图书推荐的数据集,该数据来源于goodreads网站,包含 ...
- Regularization method for machine learning
Regularization method(正则化方法) Outline Overview of Regularization L0 regularization L1 regularization ...
- 多线程&&I/O
不是操作系统的,是UNIX环境高级编程的!
- PTA循环,函数,数组作业
PTA循环实验作业 题目一:统计素数并求和 ### 1.PTA提交列表 2.设计思路(+流程图) 先定义变量(包含素数区间,循环次数,除数,素数个数记录和和的记录) 输入范围 一重循环:循环提取自然数 ...