Marriage Match II 【HDU - 3081】【并查集+二分答案+最大流】

题目链接

  一开始是想不断的把边插进去,然后再去考虑我们每次都加进去边权为1的边,直到跑到第几次就没法继续跑下去的这样的思路,果不其然的T了。

  然后,就是想办法咯,就想到了二分答案。

  首先,我们一开始处理关系,(一开始看错了男女关系,结局懵逼了好久),注意输入是女选男。然后,就是去处理咯,我们先要去考虑,女生之间为朋友的话,又由于朋友关系是可以推的,所以我们不妨用并查集去维护这层关系,并且把总的关系推上到并查集的根上去。

  然后,就是怎么样去想这个二分答案的过程了,我们可以假设玩了x轮,这么就代表了每个女孩纸被选择了x次,每个男孩纸也被选择了x次,(两者少了其中一者都不行)。那么,我们是不是可以从源点连到每个女孩纸的边权是x,然后从每个男孩纸连到汇点的边权是x。然后男孩、女孩之间的关系,就是我们之前并查集处理出来的了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 207, maxE = 3e4 + 7, st = 0;
int N, M, fr, head[maxN], cur[maxN], cnt, ed, root[maxN], mod_cnt, mod_head[maxN];
bool mp[maxN][maxN];
int fid(int x) { return x == root[x] ? x : (root[x] = fid(root[x])); }
struct Eddge
{
    int nex, to, flow;
    Eddge(int a=-1, int b=0, int c=0):nex(a), to(b), flow(c) {}
}model[maxE], edge[maxE];
inline void addEddge(int u, int v, int w)
{
    edge[cnt] = Eddge(head[u], v, w);
    head[u] = cnt++;
}
inline void _add(int u, int v, int w) { addEddge(u, v, w); addEddge(v, u, 0); }
int deep[maxN];
queue<int> Q;
inline bool bfs()
{
    for(int i=0; i<=ed; i++) deep[i] = 0;
    while(!Q.empty()) Q.pop();
    Q.push(st); deep[st] = 1;
    while(!Q.empty())
    {
        int u = Q.front(); Q.pop();
        for(int i=head[u], v, f; ~i; i=edge[i].nex)
        {
            v = edge[i].to; f = edge[i].flow;
            if(f && !deep[v])
            {
                deep[v] = deep[u] + 1;
                Q.push(v);
            }
        }
    }
    return deep[ed];
}
inline int dfs(int u, int dist)
{
    if(u == ed) return dist;
    for(int &i=cur[u], v, f; ~i; i=edge[i].nex)
    {
        v = edge[i].to; f = edge[i].flow;
        if(f && deep[v] == deep[u] + 1)
        {
            int di = dfs(v, min(dist, f));
            if(di)
            {
                edge[i].flow -= di;
                edge[i^1].flow += di;
                return di;
            }
        }
    }
    return 0;
}
inline int Dinic()
{
    int ans = 0, tmp;
    while(bfs())
    {
        for(int i=0; i<=ed; i++) cur[i] = head[i];
        while((tmp = dfs(st, INF))) ans += tmp;
    }
    return ans;
}
struct Query
{
    int u, v;
    Query(int a=0, int b=0):u(a), v(b) {}
}qes[10004];
inline void init()
{
    cnt = 0; ed = (N<<1) + 1;
    memset(head, -1, sizeof(head));
    for(int i=1; i<=N; i++) root[i] = i;
    for(int i=1; i<=N; i++) for(int j=1; j<=N; j++) mp[i][j] = false;
}
int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d%d", &N, &M, &fr);
        init();
        for(int i=1, u, v; i<=M; i++)
        {
            scanf("%d%d", &u, &v);
            mp[u][v] = true;
        }
        for(int i=1, u, v, fu, fv; i<=fr; i++)
        {
            scanf("%d%d", &u, &v);
            fu = fid(u); fv = fid(v);
            if(fu == fv) continue;
            root[fu] = fv;
            for(int j=1; j<=N; j++)
            {
                if(mp[fu][j] && !mp[fv][j]) mp[fv][j] = true;
            }
        }
        for(int i=1, u; i<=N; i++)
        {
            u = fid(i);
            for(int j=1; j<=N; j++)
            {
                if(mp[u][j]) _add(i, j + N, 1);
            }
        }
        mod_cnt = cnt;
        for(int i=0; i<cnt; i++) model[i] = edge[i];
        for(int i=0; i<=ed; i++) mod_head[i] = head[i];
        int ans = 0, l = 0, r = N, mid = 0;
        while(l <= r)
        {
            mid = (l + r) >> 1;
            cnt = mod_cnt;
            for(int i=0; i<cnt; i++) edge[i] = model[i];
            for(int i=0; i<=ed; i++) head[i] = mod_head[i];
            for(int i=1; i<=N; i++)
            {
                _add(st, i, mid);
                _add(i + N, ed, mid);
            }
            if(Dinic() >= N * mid)
            {
                ans = mid;
                l = mid + 1;
            }
            else r = mid - 1;
        }
        printf("%d\n", ans);
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/WuliWuliiii/p/11254177.html
今日推荐