POJ-1087 二分图匹配,最大流。
题意很迷,不过很水。
题意:一个房间有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;
}
POJ-1087 二分图匹配,最大流。的更多相关文章
- 最短路&生成树&二分图匹配&费用流问题
最短路 题意理解,建图 https://vjudge.net/problem/UVALive-4128 飞机票+行程建图 https://vjudge.net/problem/UVALive-3561 ...
- HDU3081:Marriage Match II (Floyd/并查集+二分图匹配/最大流(+二分))
Marriage Match II Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- cogs_14_搭配飞行员_(二分图匹配+最大流,网络流24题#01)
描述 http://cojs.tk/cogs/problem/problem.php?pid=14 有一些正飞行员和副飞行员,给出每个正飞行员可以和哪些副飞行员一起飞.一架飞机上必须一正一副,求最多多 ...
- BZOJ 3546 Life of the Party (二分图匹配-最大流)
题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3546 题意:给定一个二分图.(AB两个集合的点为n,m),边有K个.问去掉哪些点后 ...
- POJ 3041 -- 二分图匹配
题意:有个N*N的网格,有一部分格子里有陨石,小明有很牛逼的武器,打一枪后一行或一列的陨石就没了,给出陨石分布,求最小打炮数. 分析:其实就是Konig定理.记最小打炮数为m,在网格里你最多可以找出M ...
- Antenna Placement POJ - 3020 二分图匹配 匈牙利 拆点建图 最小路径覆盖
题意:图没什么用 给出一个地图 地图上有 点 一次可以覆盖2个连续 的点( 左右 或者 上下表示连续)问最少几条边可以使得每个点都被覆盖 最小路径覆盖 最小路径覆盖=|G|-最大匹配数 ...
- POJ 1274 二分图匹配
匈牙利算法 裸题 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> ...
- luogu P3386 【模板】二分图匹配
二次联通门 : luogu P3386 [模板]二分图匹配 /* luogu P3386 [模板]二分图匹配 最大流 设置源点,汇点,连到每条边上 跑一边最大流即可 */ #include <i ...
- UVA 1663 Purifying Machine (二分图匹配,最大流)
题意: 给m个长度为n的模板串,模板串由0和1和*三种组成,且每串至多1个*,代表可0可1.模板串至多匹配2个串,即*号改成0和1,如果没有*号则只能匹配自己.问:模板串可以缩减为几个,同样可以匹配原 ...
- 【最大流,二分图匹配】【hdu2063】【过山车】
题意:裸的求二分图匹配 建立一个源点 连向一边所有的点 容量为1; 另外一边点都连向汇点 容量为1; 二分图的边容量也为1 源点汇点求一遍最大流即可 #include <cstdio> ...
随机推荐
- Object.keys 函数 (JavaScript)
Object.keys 函数 (JavaScript) 返回对象的可枚举属性和方法的名称. 在实际开发中,我们有时需要知道对象的所有属性,原生js给我们提供了一个很好的方法:Object.keys() ...
- 修改CAS实现控制某个用户在定义的时间内登录次数
思想: 在数据库增加字段 1.登录次数 2.登录失败时间(类型TimeStamp) 当一个用户进来认证的时候当登录失败的时候更新登录次数 和最后登录失败的时间. 主要是在登录成功或者失败的时候判断时 ...
- IOS 设置子控件的frame(layoutSubviews and awakeFromNib)
如果控件是通过xib或者storyboard创建出来的就会调用该方法 - (void)awakeFromNib :该方法只会调用一次 // 如果控件是通过xib或者storyboard创建出来的就 ...
- 【转】android调试工具DDMS的使用详解
具体可见http://developer.android.com/tools/debugging/ddms.html. DDMS为IDE和emultor.真正的android设备架起来了一座桥梁.开发 ...
- cin对象的一些常用方法使用总结
>> 最初定义的是右移,当但是出现在 cin >>中的时候这个符号被重载了,变成了一个流操作,在用户通过键盘输入信息的时候,所有内容都会先直接存储在一个叫输入缓冲区的的地方,c ...
- java基础面试题:说说&和&&的区别
&与&&都是逻辑与 不同的是&左右两边的判断都要进行,而&&是短路与,当&&左边条件为假则不用再判断右边条件,所以效率更高 例如,对于i ...
- 火狐IE event和target的兼容
一.event对象 IE 中可以直接使用 window.event 对象,而 FF 中则不可以,解决方法之一如下: var theEvent = window.event || arguments.c ...
- PHP消息队列学习
在我们平常网站设计时,会遇到“给用户群发短信”,“商城订单系统大批量订单处理”,“商城秒杀活动”等需求,这些功能,都有一个共同的特点:就是在面对高迸发的同时,必须要保证系统处理数据的有效性.那么如何处 ...
- JZOJ 1264. 乱头发节
1264. 乱头发节(badhair.pas/c/cpp) (File IO): input:badhair.in output:badhair.out Time Limits: 1000 ms M ...
- Python知识点入门笔记——基本控制流程
复合赋值语句 在Python中,可以使用一次赋值符号,给多个变量同时赋值: 划重点:age_1,age_2 = age_2,age_1这种操作是Python独有的 i ...