【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文 ...
随机推荐
- ORB-SLAM 代码笔记(五)Frame类
Frame类的成员变量主要包含从摄像头获取的图像的 1. 特征点信息(关键点+描述字) 2. 尺寸不变特征所用金字塔信息,这些都定义在ORBextractor对象中 3. 词袋模型参数,用于跟踪失败情 ...
- thrift安装
yum -y install gcc-c++ autoconf automake sysconftool boost boost-devel libtool perl-ExtUtils-MakeMak ...
- json 处理日期格式
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") private Date createT ...
- Qt 加载Leap motion 手势识别软件 二次开发 hello world
研发需要对收拾是被进行精确定位,实现收拾的识别,和在虚拟现实中精确的显示手势在实际世界中的位置. 开始使用的Qt mingw的版本开发,总是函数没有定义,最后发现是leap sdk中需要代育vs的库文 ...
- mysql字段名与关键字重复解决办法
mysql 关键字与字段名相同,插入或者修改里会报错 解决办法: 1.改字段名,如果库里面表结构关系不复杂,修改字段名就解决 2.在插入或者修改字段时,字段名加上 ` 包上,注意:这里不是引号,是英 ...
- 问题 A: 完数
问题 A: 完数 时间限制: 1 Sec 内存限制: 32 MB提交: 252 解决: 178[提交][状态][讨论版][命题人:外部导入] 题目描述 求1-n内的完数,所谓的完数是这样的数,它的 ...
- LeetCode 29——两数相除
1. 题目 2. 解答 2.1. 方法一 题目要求不能使用乘法.除法和除余运算,但我们可以将除法转移到对数域. \[ \frac{a}{b} = e^{\frac{lna}{lnb}} = e^{ln ...
- URAL 1736 Chinese Hockey(网络最大流)
Description Sergey and Denis closely followed the Chinese Football Championship, which has just come ...
- truffle开发一个简单的Dapp
1.安装Truffle:npm install -g truffle 2.建立项目目录并进入:mkdir pet-shop-tutorial cd pet-shop-tutorial 3.使用truf ...
- $this是什么意思-成员变量和局部变量的调用
关键字$this代表其所在的当前对象 使用当前对象的属性和方法 $this->取值 方法内的局部变量 不能用$this 关键字取值 /* 和java,c++相比 方法体内想访问调用者的属性,必须 ...