您的位置:首页 > 其它

N - Marriage Match II - HDU 3081(最大流)

2015-08-13 18:28 302 查看
题目大意:有一些男孩和女孩玩一个游戏,每个女孩都可以挑一个男孩来进行这个游戏(所有人都要参加),女孩只会挑选她喜欢的男孩,并且她们认为她们朋友喜欢的男孩她们也是喜欢的(朋友的男朋友也是我的男朋友???),而且她们遵循朋友的朋友也是朋友的原则,问她们最多可以玩几轮游戏(每轮要选择的人不能和以前选择的相同)。

分析:朋友关系很明显可以使用并查集找出来每个女孩可以连接的男孩,因为要求的是最多能进行多少轮游戏,也就是在这x轮游戏中每个女孩换了x不同的男孩,每个男孩也换了x个不同的女孩,如果源点和女孩相连,汇点和男孩相连,那么流量一定是N*x,可以使用二分来查找最大的x。
下面是AC代码。
=========================================================================================================================

#include<stdio.h>
#include<string.h>
#include<queue>
#include<stack>
#include<vector>
using namespace std;

const int MAXN = 207;
const int oo = 1e9+7;

int G[MAXN][MAXN], Layer[MAXN], N, M;
int girl[MAXN*MAXN], boy[MAXN*MAXN], father[MAXN];
vector<int>love[MAXN];

int Find(int x)
{
if(father[x] != x)
father[x] = Find(father[x]);
return father[x];
}
void InIt()
{
for(int i=1; i<=N; i++)
{
father[i] = i;
love[i].clear();
}
}
void BuidGraph(int flow, int start, int End)
{
memset(G, 0, sizeof(G));

for(int i=1; i<=N; i++)
{///源点和女孩相连,汇点和男孩相连,流量是flow
G[start][i] = flow;
G[i+N][End] = flow;

int u = Find(i);///注意别用father[i]
int len = love[u].size();

for(int j=0; j<len; j++)
{///女孩和男孩之间的流量是1
G[i][love[u][j]] = 1;
}
}
}
bool BFS(int start, int End)
{
memset(Layer, 0, sizeof(Layer));
queue<int> Q;
Q.push(start);
Layer[start] = 1;

while(Q.size())
{
int u = Q.front();Q.pop();

if(u == End)return true;

for(int v=1; v<=End; v++)
{
if(Layer[v]==false && G[u][v])
{
Layer[v] = Layer[u] + 1;
Q.push(v);
}
}
}

return false;
}
int DFS(int u, int MaxFlow, int End)
{
if(u == End)return MaxFlow;

int uflow = 0;

for(int v=1; v<=End; v++)
{
if(Layer[v]==Layer[u]+1 && G[u][v])
{
int flow = min(MaxFlow-uflow, G[u][v]);
flow = DFS(v, flow, End);

G[u][v] -= flow;
G[v][u] += flow;
uflow += flow;

if(uflow == MaxFlow)
break;
}
}

if(uflow == 0)
Layer[u] = 0;
return uflow;
}
int Dinic(int start, int End)
{
int MaxFlow = 0;

while(BFS(start, End) == true)
MaxFlow += DFS(start, oo, End);

return MaxFlow;
}

int main()
{
int T;

scanf("%d", &T);

while(T--)
{
int i, F, u, v;

scanf("%d%d%d", &N, &M, &F);

InIt();

for(i=1; i<=M; i++)
scanf("%d%d", &girl[i], &boy[i]);
for(i=1; i<=F; i++)
{///用并查集合并朋友关系
scanf("%d%d", &u, &v);
u = Find(u);
v = Find(v);

if(u != v)
father[u] = v;
}

for(i=1; i<=M; i++)
{///把相同的朋友的男朋友全部都连接到根节点上,男生的区间N~2*N
u = Find(girl[i]);
love[u].push_back(boy[i]+N);
}

int start=N*2+1, End = start+1;
int left = 0, right = N, ans=0;

while(left <= right)
{
int Mid = (left+right)>>1;

BuidGraph(Mid, start, End);
int MaxFlow = Dinic(start, End);

if(MaxFlow == Mid*N)
{
left = Mid + 1;
ans = Mid;
}
else
right = Mid - 1;
}

printf("%d\n", ans);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: