【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文 ...
随机推荐
- 封装一个ExcelHelper,方便将Excel直接转成Datatable对象
public class ExcelHelper { /// <summary> /// Excel转换成DataTable /// </summary> /// <pa ...
- c++ list_iterator demo
#include <iostream> #include <list> using namespace std; typedef list<int> Integer ...
- JDBC剖析篇(2):JDBC之PreparedStatement
一次有人问我为什么要使用JDBC中的PreparedStatement,我说可以“防止SQL注入”,其他的却不能说出个一二三,现在来看看其中的秘密 参考文章: http://www.jb51.net/ ...
- 小程序如何去掉button组件的边框
小程序获取用户授权不再支持wx.getUserInfo方法,改为用button获取,格式如下 <button class="btn btn" open-type=" ...
- fiddler抓包工具的基本使用
fiddler是基于C#的HTTP抓包工具. fiddler的原理: fiddler是http代理服务器,它会抓取浏览器向服务器发送的HTTP请求,然后在将该请求发送到服务器.再获取从服务器返回的请求 ...
- vue之vue-cookies使用
一.安装vue-cookies npm install --save vue-cookies 或者 yarn add vue-cookies 二.引入vue-cookie // 方式一:require ...
- Gradle下载及安装教程
Gradle是基于Groovy语言的项目自动化建构工具,在使用Gradle之前常用的构建工具有Ant和Maven,使用这些工具我们可以用来管理项目依赖,打包,部署和发布等.使用Gradle我们将需要的 ...
- NOI中“大整数加法”问题不能AC的解决建议
一.检查输入000和00相加是否出结果. 二.数组不要开小了,亲测256的数组不够.推荐1024. 附录AC程序: 如果不能AC请将256改为1024,255改为1023. #include &l ...
- 类和实例属性的查找顺序 mro查找
如果多个类继承父类,然后又被多个类继承这种复杂的问题,可以使用 mro方法 例如: class A: pass class C(D): pass class B(D): pass class A(B, ...
- 英特尔CEO科再奇:尚未发现通过漏洞获取用户数据的行为
1月9日消息,英特尔CEO科再奇在美国西部时间1月8日举行的2018年CES中发表主题演讲,他在开场时面向产业界谈到了最近报道的安全研究发现.科再奇表示:“在我们开始之前,我想借此机会感谢整个行业,为 ...