hdu 3277(二分+最大流+拆点+离线处理+模板问题...)

Marriage Match III

Time Limit: 10000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1971    Accepted Submission(s): 583

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

Author

starvae

这个题的题意hdu 3081   几乎一样,多了个条件,就是女生还可以任选k个自己不喜欢的男生,所以等于女生多了一个容量限制,所以不能够用二分图解了,将女生拆点,将女生 i 和女生 n+i 之间连一条容量为k的边,i女生和喜欢的男生连容量为1的边,i+n和不喜欢的男生连容量为1的边,然后二分枚举完美配对上限,但是这题还卡时间,所以我们要将输入的男女生进行离线处理,先将所有的祖先结点和男生配对,然后再去寻找其孩子结点进行配对,这样的话就可以省掉一层循环了。自己的Dinic模板过不了,在网上找了个大神模板。不想学ISAP。。

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXNODE = 805;
const int MAXEDGE = MAXNODE*MAXNODE;

typedef int Type;
const Type INF = 0x3f3f3f3f;

struct Edge
{
    int u, v;
    Type cap, flow;
    Edge() {}
    Edge(int u, int v, Type cap, Type flow)
    {
        this->u = u;
        this->v = v;
        this->cap = cap;
        this->flow = flow;
    }
};

struct Dinic
{
    int n, m, s, t;
    Edge edges[MAXEDGE];
    int first[MAXNODE];
    int next[MAXEDGE];
    bool vis[MAXNODE];
    Type d[MAXNODE];
    int cur[MAXNODE];
    vector<int> cut;

    void init(int n)
    {
        this->n = n;
        memset(first, -1, sizeof(first));
        m = 0;
    }
    void add_Edge(int u, int v, Type cap)
    {
        edges[m] = Edge(u, v, cap, 0);
        next[m] = first[u];
        first[u] = m++;
        edges[m] = Edge(v, u, 0, 0);
        next[m] = first[v];
        first[v] = m++;
    }

    bool bfs()
    {
        memset(vis, false, sizeof(vis));
        queue<int> Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = true;
        while (!Q.empty())
        {
            int u = Q.front();
            Q.pop();
            for (int i = first[u]; i != -1; i = next[i])
            {
                Edge& e = edges[i];
                if (!vis[e.v] && e.cap > e.flow)
                {
                    vis[e.v] = true;
                    d[e.v] = d[u] + 1;
                    Q.push(e.v);
                }
            }
        }
        return vis[t];
    }

    Type dfs(int u, Type a)
    {
        if (u == t || a == 0) return a;
        Type flow = 0, f;
        for (int &i = cur[u]; i != -1; i = next[i])
        {
            Edge& e = edges[i];
            if (d[u] + 1 == d[e.v] && (f = dfs(e.v, min(a, e.cap - e.flow))) > 0)
            {
                e.flow += f;
                edges[i^1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0) break;
            }
        }
        return flow;
    }

    Type Maxflow(int s, int t)
    {
        this->s = s;
        this->t = t;
        Type flow = 0;
        while (bfs())
        {
            for (int i = 0; i < n; i++)
                cur[i] = first[i];
            flow += dfs(s, INF);
        }
        return flow;
    }
    void MinCut()
    {
        cut.clear();
        for (int i = 0; i < m; i += 2)
        {
            if (vis[edges[i].u] && !vis[edges[i].v])
                cut.push_back(i);
        }
    }
} gao;
const int N = 251;
bool vis[N][N];
int father[N];
int girl[N*N],boy[N*N]; ///这里m是属于 (0,n*n]的
int n,m,k,f,src,des;
int _find(int x)
{
    if(father[x]!=x)
    {
        father[x] = _find(father[x]);
    }
    return father[x];
}
void build(int c)
{
    gao.init(3*n+2);
    for(int i=1; i<=n; i++)
    {
        gao.add_Edge(src,i,c);
        gao.add_Edge(i,n+i,k);
        gao.add_Edge(2*n+i,des,c);
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=2*n+1; j<=3*n; j++)
        {
            if(vis[i][j]) gao.add_Edge(i,j,1);
            else gao.add_Edge(n+i,j,1);
        }
    }
}
int main()
{
    int tcase;
    scanf("%d",&tcase);
    while(tcase--)
    {
        scanf("%d%d%d%d",&n,&m,&k,&f);
        memset(vis,false,sizeof(vis));
        src = 0,des = 3*n+1;
        for(int i=1; i<=n; i++) father[i] = i;
        /* for(int i=1;i<=m;i++){  //TLE
             int u,v;
             scanf("%d%d",&u,&v);
             v+=2*n;
             vis[u][v] = true;
         }*/
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&girl[i],&boy[i]);
            boy[i]+=2*n;
        }
        for(int i=1; i<=f; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            int a = _find(u),b = _find(v);
            if(a!=b)
                father[a] = b;
        }
        for(int i=1; i<=m; i++)
        {
            vis[_find(girl[i])][boy[i]] = true;
        }
        for(int i=1; i<=n; i++) ///预处理所有关系
        {
            for(int j=2*n+1; j<=3*n; j++)
            {
                if(vis[i][j]) continue;
                if(vis[_find(i)][j]) vis[i][j] = true;
            }
        }
        /*for(int i=1;i<=n;i++){ //TLE
            for(int j=1;j<=n;j++){
                if(_find(i)==_find(j)){
                    for(int k=2*n+1;k<=3*n;k++){
                        if(vis[i][k]||vis[j][k]) vis[i][k] = vis[j][k] = 1;
                    }
                }
            }
        }*/
        int l = 0,r = n,ans = 0;
        while(l<=r)
        {
            int mid = (l+r)>>1;
            build(mid);
            if(gao.Maxflow(src,des)==mid*n)
            {
                ans = mid;
                l = mid+1;
            }
            else r = mid-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-10-13 10:35:23

hdu 3277(二分+最大流+拆点+离线处理+模板问题...)的相关文章

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:

hdu 4289 Control(网络流 最大流+拆点)(模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4289 Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1545    Accepted Submission(s): 677 Problem Description You, the head of Department o

POJ 3422 HDU 2686,3376 费用流拆点建图

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3376 http://acm.hdu.edu.cn/showproblem.php?pid=2686 http://poj.org/problem?id=3422 POJ 3422为从矩阵左上角走到右下角,最多走k次,每个格子里的数字只能算一次,后面可以重复经过,求经过的各个数字的和的最大值. 拆点,入点向出点连流量为1,费用为当前格子负值的边,向下方,右方连边,流量为k,费用为0,起点连流量为1,

HDU 4289 Control (最大流+拆点)

http://acm.hdu.edu.cn/showproblem.php?pid=4289 题目讲的是有一些恐怖分子要从S市去往D市,要求在一些城市中安排特工,保证一定能够抓住恐怖分子,因为安排特工需要一定的费用,所以希望找出最小的花费. 思路:可以把每个城市,即每个点拆分成进来的点和出去的点,如x点分成x和x+n,两点连接的边权值为x点上安排特工的费用.而如果x和y两点有连线,则连接x+n,y,然后求从S市到达D市的最大流.之所以能这样求,是因为在求最大流的过程中每次所更新的流量是所有边中最

hdu 4292 Food 最大流+拆点

Food Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2664    Accepted Submission(s): 899 Problem Description You, a part-time dining service worker in your college's dining hall, are now confus

HDU 3036 拆点二分最大流

Escape Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 584    Accepted Submission(s): 117 Problem Description R's girl friend D is on military training somewhere near Harbin. She feels bad ever

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

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

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

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

HDU 2686 Matrix(最大费用最大流+拆点)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2686 和POJ3422一样 删掉K把汇点与源点的容量改为2(因为有两个方向的选择)即可 #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> const int ma