POJ-1087 二分图匹配,最大流。
来源:互联网 发布:参加java培训班有用吗 编辑:程序博客网 时间:2024/05/16 15:48
A Plug for UNIX
题意很迷,不过很水。
题意:一个房间有m个插座,每个插座有一个型号,现在有n台设备,每台设备指定了一种型号的插座,接下来有k个适配器,可以代替一种型号的插座。求最少有几台设备找不到插座。
因为每个插座只能允许一台设备接入,所以很容易想到匹配问题,对,开始用二分图匹配写的成功AC,然后改成了最大流,发现最大流建图更容易,一波板子AC。但两种写法都涉及到传递闭包,还有题目有个很多小坑点,注意一下就好了。
二分图:
const int N=800+10;int n,m,k,g[N][N],linked[N],used[N];void floyd(int num)//传递闭包{// printf("%d\n",num); for(int k=1; k<=num; k++) for(int i=1; i<=num; i++) for(int j=1; j<=num; j++) g[i][j]=g[i][j]||(g[i][k]&&g[k][j]);// for(int i=1;i<num;i++)// for(int j=1;j<num;j++)// printf("i=%d j=%d %d\n",i,j,g[i][j]);}bool dfs(int u){ for(int i=1; i<=m; i++) if(!used[i]&&g[u][i]) { used[i]=1; if(linked[i]==-1||dfs(linked[i])) { linked[i]=u; return true; } } return false;}int hungary(){ int res=0; memset(linked,-1,sizeof(linked)); for(int i=m+n+101;i<=m+n+101+n;i++) { memset(used,0,sizeof(used)); if(dfs(i)) res++; } return n-res;}int main(){ while(~scanf("%d",&m)) { memset(g,0,sizeof(g)); map<string,int>q; map<string,int>q1; string plug,dev; for(int i=1; i<=m; i++) { cin>>plug; q[plug]=i; } scanf("%d",&n); int tmpn=m+n+100,tmpm=m; for(int i=1; i<=n; i++) { cin>>dev>>plug; q1[dev]=++tmpn; if(!q[plug]) q[plug]=++tmpm; g[q1[dev]][q[plug]]=1; } scanf("%d",&k); for(int i=1; i<=k; i++) { cin>>dev>>plug; if(!q[dev]) q[dev]=++tmpm; if(!q[plug]) q[plug]=++tmpm; g[q[dev]][q[plug]]=1;//单向传递// g[q[plug]][q[dev]]=1; } floyd(tmpn); printf("%d\n",hungary()); } return 0;}最大流:用0作为源点,与所有设备连边,容量为1,设备与对应型号插座连边,容量为1,别忘了传递闭包。插座和汇点连边,容量为1。注意,后出现的插座不能和汇点连边。
const int N=800+10;int n,m,k;int maze[N][N];int gap[N],dis[N],pre[N],cur[N];int flow[N][N];void floyd(int num)//电器与插头之间传递闭包{ for(int k=1; k<=num; k++) for(int i=1; i<=num; i++) for(int j=1; j<=num; j++) maze[i][j]|=maze[i][k]&&maze[k][j];}int sap(int s,int t,int num){ memset(cur,0,sizeof(cur)); memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); memset(flow,0,sizeof(flow)); int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=num; while(dis[s]<num) {loop: for(int v=cur[u]; v<num; v++) if(maze[u][v]-flow[u][v]&&dis[u]==dis[v]+1) { if(aug==-1||aug>maze[u][v]-flow[u][v]) aug=maze[u][v]-flow[u][v]; pre[v]=u; u=cur[u]=v; if(v==t) { maxflow+=aug; for(u=pre[u]; v!=s; v=u,u=pre[u]) { flow[u][v]+=aug; flow[v][u]-=aug; } aug=-1; } goto loop; } int mid=num-1; for(int v=0; v<num; v++) if(maze[u][v]-flow[u][v]&&mid>dis[v]) { cur[u]=v; mid=dis[v]; } if((--gap[dis[u]])==0) break; gap[dis[u]=mid+1]++; u=pre[u]; } return n-maxflow;}int main(){ while(~scanf("%d",&m)) { string dev,plug; map<string,int>q; map<string,int>q1; memset(maze,0,sizeof(maze)); //1-n为电器,101开始都是插头 //原点为0,汇点为301--最坏情况; int num=100,hui=301; for(int i=1; i<=m; i++) { cin>>plug; q[plug]=++num; maze[q[plug]][hui]=1;//插头到汇点的容量为1; } scanf("%d",&n); for(int i=1; i<=n; i++) { cin>>dev>>plug; q1[dev]=i; maze[0][i]=1;//源点到电器,容量为1 if(!q[plug]) q[plug]=++num; maze[i][q[plug]]=1;//电器到插头的容量为1; } scanf("%d",&k); for(int i=1; i<=k; i++) { cin>>dev>>plug; if(!q[dev]) q[dev]=++num; if(!q[plug]) q[plug]=++num; maze[q[dev]][q[plug]]=1; } floyd(300); printf("%d\n",sap(0,301,302)); } return 0;}
阅读全文
0 0
- POJ-1087 二分图匹配,最大流。
- poj 2112 最大流求二分图匹配/二分搜索
- poj 1087 A Plug for UNIX 二分图最大匹配
- Poj 2112 [最大流] [二分图的多重匹配]
- POJ 3894 System Engineer 二分图匹配 Hopcroft_Carp 最大流
- poj 2226 最大流二分匹配
- POJ 1274 二分图最大匹配
- POJ 1469 二分图最大匹配
- POJ 2239 二分图最大匹配
- Asteroids(poj 3041,二分图最大匹配)
- poj 1274 二分图 最大匹配
- poj 1469 二分图最大匹配
- POJ 1469二分图最大匹配
- poj 1274 二分图最大匹配
- POJ 1469 二分图最大匹配 COURSES
- poj 2446 二分图 最大匹配
- poj 2536 二分图 最大匹配
- POJ 3692 二分图最大匹配
- ProtocolBuffer的简单使用
- win7系统如何打开dos窗口
- 我爱江山或过无过过过过过过
- 算法系列——Contains Duplicate
- Qt使用QSS
- POJ-1087 二分图匹配,最大流。
- Web服务器使用JSP来创建网页的步骤
- vi命令
- 『数据结构』RMQ 问题
- 算法系列——Contains Duplicate II
- 算法系列——Contains Duplicate III
- linux之如何在任意目录执行我常用的脚本文件
- python学习笔记——控制流(if,while,for,break,continue,模拟登录小程序实例)
- SUSELinux安装weblogic-db2-IBM