HDU 3277 Marriage Match III(并查集+二分答案+最大流SAP)拆点,经典
Marriage Match III
Time Limit: 10000/4000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1581 Accepted Submission(s): 464
quarrel breaks out, but we will still play together after that, because we are kids.
Now, there are 2n kids, n boys numbered from 1 to n, and n girls numbered from 1 to n. As you know, ladies first. So, every girl can choose a boy first, with whom she has not quarreled, to make up a family. Besides, the girl X can also choose boy Z to be her
boyfriend when her friend, girl Y has not quarreled with him. Furthermore, the friendship is mutual, which means a and c are friends provided that a and b are friends and b and c are friend.
Once every girl finds their boyfriends they will start a new round of this game—marriage match. At the end of each round, every girl will start to find a new boyfriend, who she has not chosen before. So the game goes on and on. On the other hand, in order to
play more times of marriage match, every girl can accept any K boys. If a girl chooses a boy, the boy must accept her unconditionally whether they had quarreled before or not.
Now, here is the question for you, how many rounds can these 2n kids totally play this game?
Each test case starts with three integer n, m, K and f in a line (3<=n<=250, 0<m<n*n, 0<=f<n). n means there are 2*n children, n girls(number from 1 to n) and n boys(number from 1 to n).
Then m lines follow. Each line contains two numbers a and b, means girl a and boy b had never quarreled with each other.
Then f lines follow. Each line contains two numbers c and d, means girl c and girl d are good friends.
1
4 5 1 2
1 1
2 3
3 2
4 2
4 4
1 4
2 3
3
一组配对情况为全部的女性都有一个与之配对的男性(一对一的关系)。假设还有其它组配对情况,那么全部的女性配对不能够再与原来的男性配成对。问最多有多少组配对情况。
可是由于能够任意选择K个人。
所以要将女孩拆成两个点。
将每一个女孩u分为u1,u2。若u喜欢v则加一条u1到v的边 否则加一条u2到v的边。令加u1到u2的容量为k的边;
这个拆点的想法很巧妙。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define captype int const int MAXN = 100010; //点的总数
const int MAXM = 4000100; //边的总数
const int INF = 1<<30;
struct EDG{
int to,next;
captype cap,flow;
}edg[MAXM];
int eid,head[MAXN];
int gap[MAXN];
int dis[MAXN];
int cur[MAXN];
int pre[MAXN]; void init(){
eid=0;
memset(head,-1,sizeof(head));
}
void addEdg(int u,int v,captype c,captype rc=0){
edg[eid].to=v; edg[eid].next=head[u];
edg[eid].cap=c; edg[eid].flow=0; head[u]=eid++; edg[eid].to=u; edg[eid].next=head[v];
edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++;
}
captype maxFlow_sap(int s,int t,int n){
memset(gap,0,sizeof(gap));
memset(dis,0,sizeof(dis));
memcpy(cur,head,sizeof(head));
pre[s]=-1;
gap[0]=n; captype ans=0;
int u=s;
while(dis[s]<n){
if(u==t){
captype mint=INF;
int id;
for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to])
if(mint>edg[i].cap-edg[i].flow){
mint=edg[i].cap-edg[i].flow;
id=i;
}
for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to]){
edg[i].flow+=mint;
edg[i^1].flow-=mint;
}
ans+=mint;
u=edg[id^1].to;
continue;
}
bool flag=0;
for(int i=cur[u]; i!=-1; i=edg[i].next)
if(edg[i].cap>edg[i].flow&&dis[u]==dis[edg[i].to]+1){
cur[u]=pre[edg[i].to]=i;
flag=true;
break;
}
if(flag){
u=edg[cur[u]].to;
continue;
}
int minh=n;
for(int i=head[u]; i!=-1; i=edg[i].next)
if(edg[i].cap>edg[i].flow && minh>dis[edg[i].to]){
cur[u]=i; minh=dis[edg[i].to];
}
gap[dis[u]]--;
if(!gap[dis[u]]) return ans;
dis[u]=minh+1;
gap[dis[u]]++;
if(u!=s)
u=edg[pre[u]^1].to;
}
return ans;
} int fath[MAXN];
int findroot(int x){
if(x!=fath[x])
fath[x]=findroot(fath[x]);
return fath[x];
}
void setroot(int x,int y){
x=findroot(x);
y=findroot(y);
fath[x]=y;
}
void rebuildMap(int mapt[255][255],int n){//处理朋友之间的关系
int mp[255][255]={0};
for(int i=1; i<=n; i++)
fath[i]=findroot(i);
for(int i=1; i<=n; i++){
int j=fath[i];
for(int e=1; e<=n; e++)
mp[j][e]|=mapt[i][e];
}
for(int i=1; i<=n; i++){
int j=fath[i];
for(int e=1; e<=n; e++)
mapt[i][e]=mp[j][e];
}
}
int main()
{
int T,n,m,k,f,mapt[255][255];
int u,v;
scanf("%d",&T);
while(T--){
scanf("%d%d%d%d",&n,&m,&k,&f); init();
memset(mapt,0,sizeof(mapt));
for(int i=1; i<=n; i++)
fath[i]=i; while(m--){
scanf("%d%d",&u,&v);
mapt[u][v]=1;
}
while(f--){
scanf("%d%d",&u,&v);
setroot(u,v);
}
rebuildMap(mapt,n); int s=0, t=3*n+1;
for(int i=1; i<=n; i++){
addEdg(s,i,0);
addEdg(i,i+n,k);
for(int j=1; j<=n; j++)
if(mapt[i][j])
addEdg(i,j+2*n,1);
else
addEdg(i+n,j+2*n,1); addEdg(i+2*n,t,0);
} int ans=0 , l=0 , r=n ,mid;
while(l<=r){
mid=(l+r)>>1; for(int i=0; i<eid; i++)
edg[i].flow=0;
for(int i=head[s]; i!=-1; i=edg[i].next)
edg[i].cap=mid;
for(int i=head[t]; i!=-1; i=edg[i].next)
edg[i^1].cap=mid; if(n*mid==maxFlow_sap(s,t,t+1))
ans=mid,l=mid+1;
else
r=mid-1;
} printf("%d\n",ans);
}
}
HDU 3277 Marriage Match III(并查集+二分答案+最大流SAP)拆点,经典的更多相关文章
- HDU 3277 Marriage Match III(二分+最大流)
HDU 3277 Marriage Match III 题目链接 题意:n个女孩n个男孩,每一个女孩能够和一些男孩配对,此外还能够和k个随意的男孩配对.然后有些女孩是朋友,满足这个朋友圈里面的人.假设 ...
- HDU 3277 Marriage Match III
Marriage Match III Time Limit: 4000ms Memory Limit: 32768KB This problem will be judged on HDU. Orig ...
- Marriage Match II 【HDU - 3081】【并查集+二分答案+最大流】
题目链接 一开始是想不断的把边插进去,然后再去考虑我们每次都加进去边权为1的边,直到跑到第几次就没法继续跑下去的这样的思路,果不其然的T了. 然后,就是想办法咯,就想到了二分答案. 首先,我们一开始处 ...
- HDU 3416 Marriage Match IV (最短路径,网络流,最大流)
HDU 3416 Marriage Match IV (最短路径,网络流,最大流) Description Do not sincere non-interference. Like that sho ...
- hdu 4750 Count The Pairs(并查集+二分)
Problem Description With the 60th anniversary celebration of Nanjing University of Science and Techn ...
- 【HDOJ】3277 Marriage Match III
Dinic不同实现的效率果然不同啊. /* 3277 */ #include <iostream> #include <string> #include <map> ...
- HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)
HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...
- HDU 3081 Marriage Match II (二分图,并查集)
HDU 3081 Marriage Match II (二分图,并查集) Description Presumably, you all have known the question of stab ...
- HDU 3081 Marriage Match II(二分法+最大流量)
HDU 3081 Marriage Match II pid=3081" target="_blank" style="">题目链接 题意:n个 ...
随机推荐
- C#编程的语法积累(一)
1.自动属性 之前的实现方式: private int id; public int Id { set {id = value;} get {return id;} } 现在可通过自动属性实现: pu ...
- python全栈开发day43-javascript
一.昨日内容回顾 1.绝对定位的盒子居中 left:50%: margin-left:负的盒子宽度的一半 2.固定位置 脱离标准文档流 作用:返回顶部,广告,滚动监听栏.固定导航栏(body{marg ...
- fork调用的底层实现
fork调用的内核实现: http://www.cnblogs.com/huangwei/archive/2010/05/21/1740794.html http://blog.csdn.net/he ...
- hdu 1251:统计难题[【trie树】||【map】
<题目链接> 统计难题 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131 ...
- [译]javascript中的依赖注入
前言 在上文介绍过控制反转之后,本来打算写篇文章介绍下控制反转的常见模式-依赖注入.在翻看资料的时候,发现了一篇好文Dependency injection in JavaScript,就不自己折腾了 ...
- python新手总结(二)
random模块 随机小数 random uniform 随机整数 randint randrange 随机抽取 choice sample 打乱顺序 shuffle random.random() ...
- Javascript中call,apply,bind的区别
一.探索call方法原理 Function.prototype.call = function(obj) { // 1.让fn中的this指向obj // eval(this.toString().r ...
- 5.27 Test
1.COGS.2039. 树的统计 思路: 各种方法. 代码: 1.遍历树1 时间 0.314 s 平均内存 2.96 MB #include<cstdio> using name ...
- 洛谷.2325.[SCOI2005]王室联邦(贪心)
题目链接 比较水的题 然而.. 首先可以考虑DFS 每B个分一个块,但是这样链底不会和上边相连 于是考虑从底下开始分,即在DFS完一个点时才将其加入栈中:当子树size==B时出栈 最后在根节点可能会 ...
- ftp不能登录报错
虚拟机装好RedHat后,准备使用filezilla连接,输入IP地址,root用户,密码,快速连接,报错: 530 Permission denied. 故障排除: 1.首先检查系统是否开启了vsf ...