zoukankan      html  css  js  c++  java
  • UVALive-2966 King's Quest(强连通+二分图匹配)

    题目大意:有n个男孩和和n个女孩,已只每个男孩喜欢的女孩。一个男孩只能娶一个女孩、一个女孩只能嫁一个男孩并且男孩只娶自己喜欢的女孩,现在已知一种他们的结婚方案,现在要求找出每个男孩可以娶的女孩(娶完之后不能影响其他男孩结婚)。

    题目分析:已知的结婚方案是一个完全匹配。从每个男孩出发向他喜欢的女孩连一条有向边,得到一张完全二分图,实际上这道题是让判断去掉哪一些边使图仍然完全匹配。设男生x1和女生y1是已知方案中要结婚的两个人,假如x1抛弃y1,选择了他也喜欢的y2结婚(也就是去掉边x1->y2),那么就得需要让原方案中y2的结婚对象x2选择一个他喜欢的女孩(不能再是y2)结婚,一直进行下去这个过程,y1终究会被选走(如果去边之后的图仍完全匹配)。这正是匈牙利算法的过程,但这样要超时。但是,如果将从y1出发连一条边到x1,那么这个过程所经过的所有点就构成了一个强连通分量。对于某个男孩,娶和他在同一强连通分量的任何一个女孩都不会影响其他男孩结婚。

    代码如下:

    # include<iostream>
    # include<cstdio>
    # include<stack>
    # include<vector>
    # include<cstring>
    # include<iostream>
    using namespace std;
    # define REP(i,s,n) for(int i=s;i<n;++i)
    # define CL(a,b) memset(a,b,sizeof(a))
    # define CLL(a,b,n) fill(a,a+n,b)
    
    const int N=2005;
    struct Edge
    {
        int to,nxt;
    };
    Edge e[N*100+N];
    stack<int>S;
    int scc_cnt,dfs_cnt,cnt,n,head[2*N],sccno[2*N];
    int low[2*N],pre[2*N],G[N][N];
    vector<int>ans;
    
    void add(int u,int v)
    {
        e[cnt].to=v;
        e[cnt].nxt=head[u];
        head[u]=cnt++;
    }
    
    void dfs(int u)
    {
        S.push(u);
        low[u]=pre[u]=++dfs_cnt;
        for(int i=head[u];i!=-1;i=e[i].nxt){
            int v=e[i].to;
            if(!pre[v]){
                dfs(v);
                low[u]=min(low[u],low[v]);
            }else if(!sccno[v])
                low[u]=min(low[u],pre[v]);
        }
        if(low[u]==pre[u]){
            ++scc_cnt;
            while(1){
                int x=S.top(); S.pop();
                sccno[x]=scc_cnt;
                if(x==u) break;
            }
        }
    }
    
    void findScc()
    {
        scc_cnt=dfs_cnt=0;
        CL(pre,0);
        CL(sccno,0);
        REP(i,1,n+1) if(!pre[i]) dfs(i);
    }
    
    int main()
    {
        while(~scanf("%d",&n))
        {
            int k,a;
            cnt=0;
            CL(G,0);
            CL(head,-1);
            REP(i,1,n+1){
                scanf("%d",&k);
                while(k--)
                {
                    scanf("%d",&a);
                    add(i,a+n);
                    G[i][a]=1;
                }
            }
            REP(i,1,n+1){
                scanf("%d",&a);
                add(a+n,i);
            }
            findScc();
            REP(i,1,n+1){
                ans.clear();
                REP(j,n+1,2*n+1) if(G[i][j-n]&&sccno[i]==sccno[j])
                    ans.push_back(j-n);
                printf("%d",ans.size());
                REP(j,0,ans.size()) printf(" %d",ans[j]);
                printf("
    ");
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    leetcode_1423. 可获得的最大点数
    leetcode_剑指 Offer 06. 从尾到头打印链表
    leetcode_剑指 Offer 05. 替换空格
    leetcode_49. 字母异位词分组
    leetcode_73. 矩阵置零
    leetcode_26. 删除排序数组中的重复项
    jstack查看JVM堆栈信息
    如何画一张架构图
    百年孤独家谱
    阿尔萨斯(Arthas)入门
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/4947183.html
Copyright © 2011-2022 走看看