zoukankan      html  css  js  c++  java
  • King's Quest---poj1904(连通图缩点)

    题目链接:http://poj.org/problem?id=1904

    题意:国王有n个儿子,每个儿子喜欢ki个女孩,国王想让王子与他喜欢的人结婚,就让巫师做一个列表出来,但是国王想知道王子能和哪些女孩结婚,并且不影响其他王子也能与自己喜欢的女孩在一起;

    其实就是求王子能和哪些女孩结婚,不影响最大匹配;

     假如已知匹配王子属于x,女孩属于y

    现有匹配xi---yi xj---yj 并且xi也喜欢yj

    如果说xi能和yj匹配并不改变匹配总数,必须满足一下两个条件之一:

    1:xj也喜欢yi;

    2:yi 被某个匹配中的 xk喜欢,并且 xi 也喜欢 yk ;

    思路很像匈牙利算法中找曾广路的过程;xi--->yj--->xk--->yi--->xi(是一个环,各点都能相互到达,所以其中的匹配可以互换,并且不影响匹配总数);

     

    建图:王子u喜欢女孩v,则u到v连一条边。对于给出的初始完美匹配,王子u与女孩v匹配,则v到u连一条边。然后求SCC。

    显然对于同一个SCC中王子数目和女孩数目是相等的,并且从某个王子出发能够到达所有女孩,这样,王子可以和属于同一个SCC中的任意一个女孩结婚,而不会影响其他王子。

    #include<stdio.h>
    #include<string.h>
    #include<vector>
    #include<algorithm>
    using namespace std;
    #define met(a, b) memset(a, b, sizeof(a))
    const int N = 4050;
    
    int n, low[N], dfn[N], Time;
    int IsSta[N], Sta[N], top, Belong[N], cnt, ans[N];
    vector<vector<int> >G;
    
    void Init()
    {
        met(low, 0);
        met(dfn, 0);
        met(IsSta, 0);
        met(Sta, 0);
        met(Belong, 0);
        G.clear();
        G.resize(N+1);
        Time = cnt = top = 0;
    }
    
    void Tarjan(int u)
    {
        low[u] = dfn[u] = ++ Time;
        IsSta[u] = 1;
        Sta[top++] = u;
        int len = G[u].size(), v;
        for(int i=0; i<len; i++)
        {
            v = G[u][i];
            if(!dfn[v])
            {
                Tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if(IsSta[v])
                low[u] = min(low[u], dfn[v]);
        }
        if(low[u] == dfn[u])
        {
            ++ cnt;
            do
            {
                v = Sta[--top];
                IsSta[v] = 0;
                Belong[v] = cnt;
            }while(u != v);
        }
    }
    
    int main()
    {
        while(scanf("%d", &n) != EOF)
        {
            Init();
    
            int k, x;
    
            for(int i=1; i<=n; i++)
            {
                scanf("%d", &k);
                for(int j=1; j<=k; j++)
                {
                    scanf("%d", &x);
                    G[i].push_back(x+n);///王子编号为1---n,公主编号为n+1---2*n;
                }
            }
            for(int i=1; i<=n; i++)
            {
                scanf("%d", &x);
                G[x+n].push_back(i);///添加反向边;
            }
    
            for(int i=1; i<=n; i++)
            {
                if(!dfn[i])
                    Tarjan(i);
            }
    
            for(int i=1; i<=n; i++)
            {
                int len = G[i].size(), u = Belong[i], v;
    
                met(ans, 0);
                int K = 0;
    
                for(int j=0; j<len; j++)
                {
                    v = Belong[ G[i][j] ];
                    if( u == v )///当他们在一个块中时是可以与之匹配的;
                        ans[K++] = G[i][j];
                }
    
                sort(ans, ans+K);
    
                printf("%d", K);
                for(int j=0; j<K; j++)
                    printf(" %d", ans[j]-n);///恢复原编号;
                printf("
    ");
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    py计算程序运行时间-简易版
    py-冒泡排序
    py_冒泡排序
    Python测试函数运行时间
    py_二分查找
    Python发送get、post请求
    py_递归实例:汉诺塔问题
    递归实例:汉诺塔问题
    Jmeter断言实例—响应断言
    第十四天-linux命令及基础知识实战
  • 原文地址:https://www.cnblogs.com/zhengguiping--9876/p/5676699.html
Copyright © 2011-2022 走看看