HDU 3277 Marriage Match III(拆点+二分+最大流SAP)

这个题目是说,有n个女的和男的找伴侣。然后女的具有主动选择权,每个女的可以选自己喜欢的男的,也可以挑选k个不喜欢的男的,做法就是:把女的拆点,u1->u2建立一条容量为k的边。如果遇见喜欢的男生i->j+2*n建一条容量为1的边,否则i+n->j+2*n建一条容量为1的边。最后将源点和女生相连容量为mid,汇点与男生相连容量为mid。枚举mid,看是否会产生满流。

可能姿势不够优美dinic超时了啊,换成SAP快了很多啊、、、

Marriage Match III

Time Limit: 10000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1405    Accepted Submission(s): 421

Problem Description

Presumably, you all have known the question of stable marriage match. A girl will choose a boy; it is similar as the ever game of play-house . What a happy time as so many friends play together. And it is normal that a fight or a 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?

Input

There are several test cases. First is an integer T, means the number of test cases.

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.

Output

For each case, output a number in one line. The maximal number of Marriage Match the children can play.

Sample Input

1
4 5 1 2
1 1
2 3
3 2
4 2
4 4
1 4
2 3

Sample Output

3
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define eps 1e-12
///#define M 1000100
#define LL __int64
///#define LL long long
///#define INF 0x7ffffff
#define INF 0x3ffffff
#define PI 3.1415926535898
#define zero(x) ((fabs(x)<eps)?0:x)

using namespace std;

const int maxn = 1010;

///int deep[maxn];
int cnt;
int n, m, k;
int S, T;
int fa[maxn];
int vis[maxn][maxn];
int cur[maxn], head[maxn];
int dis[maxn], gap[maxn];
int aug[maxn], pre[maxn];

struct node
{
    int v, w;
    int next;
} f[510000];

struct node1
{
    int l, r;
} pp[50010];

int Find(int x)
{
    if(x != fa[x]) fa[x] = Find(fa[x]);
    return fa[x];
}
void Union(int x,int y)
{
    int xx,yy;
    xx=Find(x);
    yy=Find(y);
    if(xx!=yy)
        fa[xx]=yy;
}

void init()
{
    cnt = 0;
    memset(head, -1, sizeof(head));
    for(int i = 1; i <= n; i++) fa[i] = i;
}
void add(int u, int v, int w)
{
    f[cnt].v = v;
    f[cnt].w = w;
    f[cnt].next = head[u];
    head[u] = cnt++;

    f[cnt].v = u;
    f[cnt].w = 0;
    f[cnt].next = head[v];
    head[v] = cnt++;
}

int SAP(int s, int e, int n)
{
    int max_flow = 0, v, u = s;
    int id, mindis;
    aug[s] = INF;
    pre[s] = -1;
    memset(dis, 0, sizeof(dis));
    memset(gap, 0, sizeof(gap));
    gap[0] = n;
    for (int i = 0; i <= n; ++i)  cur[i] = head[i];/// 初始化当前弧为第一条弧
    while (dis[s] < n)
    {
        bool flag = false;
        if (u == e)
        {
            max_flow += aug[e];
            for (v = pre[e]; v != -1; v = pre[v]) /// 路径回溯更新残留网络
            {
                id = cur[v];
                f[id].w -= aug[e];
                f[id^1].w += aug[e];
                aug[v] -= aug[e]; /// 修改可增广量,以后会用到
                if (f[id].w == 0) u = v; /// 不回退到源点,仅回退到容量为0的弧的弧尾
            }
        }
        for (id = cur[u]; id != -1; id = f[id].next)/// 从当前弧开始查找允许弧
        {
            v = f[id].v;
            if (f[id].w > 0 && dis[u] == dis[v] + 1) /// 找到允许弧
            {
                flag = true;
                pre[v] = u;
                cur[u] = id;
                aug[v] = min(aug[u], f[id].w);
                u = v;
                break;
            }
        }
        if (flag == false)
        {
            if (--gap[dis[u]] == 0) break; ///gap优化,层次树出现断层则结束算法
            mindis = n;
            cur[u] = head[u];
            for (id = head[u]; id != -1; id = f[id].next)
            {
                v = f[id].v;
                if (f[id].w > 0 && dis[v] < mindis)
                {
                    mindis = dis[v];
                    cur[u] = id; /// 修改标号的同时修改当前弧
                }
            }
            dis[u] = mindis + 1;
            gap[dis[u]]++;
            if (u != s) u = pre[u]; /// 回溯继续寻找允许弧
        }
    }
    return max_flow;
}

void build(int mid)
{
    int a, b;
    cnt = 0;
    memset(head, -1, sizeof(head));
    S = 0;
    T = 3*n+1;
    for(int i = 1 ; i <= n; i++)
    {
        add(S, i, mid);
        add(i+2*n, T, mid);
        add(i, i+n, k);
    }
    memset(vis, 0, sizeof(vis));
    for(int i = 0; i < m; i++)
    {
        a = pp[i].l;
        b = pp[i].r;
        vis[Find(a)][b] = 1;
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            if(!vis[Find(i)][j]) add(i+n, j+2*n, 1);
            else add(i, j+2*n, 1);
        }
    }
}
int main()
{
    int K;
    cin >>K;
    while(K--)
    {
        int p;
        scanf("%d %d %d %d",&n, &m, &k, &p);
        init();
        for(int i = 0; i < m; i++) scanf("%d %d",&pp[i].l, &pp[i].r);
        int x, y;
        while(p--)
        {
            scanf("%d %d",&x, &y);
            Union(x, y);
        }
        int l = 0;
        int r = n;
        int ans = 0;
        int mid;
        while(l <= r)
        {
            mid = (l+r)>>1;
            build(mid);
            if(SAP(0, 3*n+1, 3*n+2) >= n*mid)
            {
                l = mid+1;
                ans = mid;
                continue;
            }
            r = mid-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

HDU 3277 Marriage Match III(拆点+二分+最大流SAP)

时间: 2024-08-10 15:09:04

HDU 3277 Marriage Match III(拆点+二分+最大流SAP)的相关文章

HDU 3277 Marriage Match III(二分+最大流)

HDU 3277 Marriage Match III 题目链接 题意:n个女孩n个男孩,每个女孩可以和一些男孩配对,此外还可以和k个任意的男孩配对,然后有些女孩是朋友,满足这个朋友圈里面的人,如果有一个能和某个男孩配对,其他就都可以,然后每轮要求每个女孩匹配到一个男孩,且每轮匹配到的都不同,问最多能匹配几轮 思路,比HDU3081多了一个条件,此外可以和k个任意的男孩配对,转化为模型,就是多了一个结点,有两种两边的方式,一种连向可以配对的,一种连向不能配对的,此外还要保证流量算在一起,这要怎么

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 Problem Description Presumably, you all have known the question of stable marriage match.

hdu 3277 Marriage Match III【最大流+并查集+二分枚举】

Marriage Match III Time Limit: 10000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1491    Accepted Submission(s): 440 Problem Description Presumably, you all have known the question of stable marriage match.

HDU 3277 Marriage Match III

Marriage Match III Time Limit: 4000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 327764-bit integer IO format: %I64d      Java class name: Main Presumably, you all have known the question of stable marriage match. A girl w

HDU 3416 Marriage Match IV(最短路+最大流)

HDU 3416 Marriage Match IV 题目链接 题意:给一个有向图,给定起点终点,问最多多少条点可以重复,边不能重复的最短路 思路:边不能重复,以为着每个边的容量就是1了,最大流问题,那么问题只要能把最短路上的边找出来,跑一下最大流即可,判断一条边是否是最短路上的边,就从起点和终点各做一次dijstra,求出最短路距离后,如果一条边满足d1[u] + d2[v] + w(u, v) == Mindist,那么这条边就是了 代码: #include <cstdio> #inclu

hdu 3416 Marriage Match IV (最短路+最大流)

hdu 3416 Marriage Match IV Description Do not sincere non-interference. Like that show, now starvae also take part in a show, but it take place between city A and B. Starvae is in city A and girls are in city B. Every time starvae can get to city B a

【HDOJ】3277 Marriage Match III

Dinic不同实现的效率果然不同啊. 1 /* 3277 */ 2 #include <iostream> 3 #include <string> 4 #include <map> 5 #include <queue> 6 #include <set> 7 #include <stack> 8 #include <vector> 9 #include <deque> 10 #include <algori

hdu 3416 Marriage Match IV 【 最短路 最大流 】

求边不可重复的最短路条数 先从起点到终点用一次dijkstra,再从终点到起点用一次dijkstra,来判断一条边是否在最短路上 如果在,就将这条边的两个端点连起来,容量为1 再跑一下dinic(),最大流就是不可重复的最短路条数 还是想不到怎么建图啊------ 每次做网络流的题目--- 诶---该怎么建图啊--- 想了一会儿----啊--不会啊--- 搜一下题解吧--- 啊,原来这样连边啊--- 啊,原来需要---floyd / 并查集 /dijkstra /------ 啊---快,粘一粘

hdu 3081 hdu 3277 hdu 3416 Marriage Match II III IV //最大流的灵活运用

3081 题意: n个女孩选择没有与自己吵过架的男孩有连边(自己的朋友也算,并查集处理),2分图,有些边,求有几种完美匹配(每次匹配每个点都不重复匹配) 我是建二分图后,每次增广一单位,(一次完美匹配),再修改起点还有终点的边流量,继续增广,直到达不到完美匹配为止.网上很多是用二分做的,我觉得没必要...(网上传播跟风真严重...很多人都不是真正懂最大流算法的...) 3277 : 再附加一条件,每个女孩可以最多与k个自己不喜欢的男孩.求有几种完美匹配(同上). 我觉得:求出上题答案,直接ans