zoukankan      html  css  js  c++  java
  • POJ 1904 King's Quest ★(强连通分量:可行完美匹配边)

    题意

    有n个女生和n个男生,给定一些关系表示男生喜欢女生(即两个人可以结婚),再给定一个初始匹配,表示这个男生和哪个女生结婚,初始匹配必定是合法的.求每个男生可以和哪几个女生可以结婚且能与所有人不发生冲突。

    思路

    好题啊。。。没想到强连通分量还能应用到完美匹配上。。。 将男生从1到n编号,女生从(n+1)到2*n编号,输入时如果男生u可以和女生v结婚,那么就做一条从u到v的边(u,v),对于输入的初始匹配(u,v)(表示男生u和女生v结婚),那么从v做一条到u的边(v,u),然后求解改图的强连通分量,如果男生和他喜欢的女生在同一个强连通分量内,则他们可以结婚(匹配) 为什么呢?因为如果这个男生找另一个女生结婚,则因为在同一个强连通分量中,则这个女生到男生原配存在路径,那么这样原配一定存在别的某个男生可以和她结婚。 抽象一下,求所有可行的完美匹配边①按原图建立无向边形成二分图。 ②求出任意一个完美匹配。 ③建立新图,原图改为有向边<i, j>,并且对于每一个完美匹配(i, j),连一条<j, i>的边。 ④求强连通分量,如果原图某条边<i, j>两点在同一个强连通分量,则该边可以是完美匹配边。  

    代码

     
    using namespace std;
    const int MAXN = 4005;
    const int MAXM = 205005;
    struct SCC{
        int scc_num, scc[MAXN];         //强连通分量总数、每个节点所属的强连通分量
        vector  scc_node[MAXN];    //强连通分量中的节点
        stack  st;
        int dfn[MAXN], low[MAXN], id;
        bool vis[MAXN], instack[MAXN];
        int cnt, head[MAXN];
    
        struct node{
            int u, v;
            int next;
        }arc[MAXM];
    
        void init(){
            cnt = 0;
            mem(head, -1);
            return ;
        }
        void add(int u, int v){
            arc[cnt].u = u;
            arc[cnt].v = v;
            arc[cnt].next = head[u];
            head[u] = cnt ++;
        }
        void dfs(int u){
            vis[u] = instack[u] = 1;
            st.push(u);
            dfn[u] = low[u] = ++ id;
            for (int i = head[u]; i != -1; i = arc[i].next){
                int v = arc[i].v;
                if (!vis[v]){
                    dfs(v);
                    low[u] = min(low[u], low[v]);
                }
                else if (instack[v]){
                    low[u] = min(low[u], dfn[v]);
                }
            }
            if (low[u] == dfn[u]){
                ++ scc_num;
                while(st.top() != u){
                    scc[st.top()] = scc_num;
                    scc_node[scc_num].push_back(st.top());
                    instack[st.top()] = 0;
                    st.pop();
                }
                scc[st.top()] = scc_num;
                scc_node[scc_num].push_back(st.top());
                instack[st.top()] = 0;
                st.pop();
            }
            return ;
        }
        void tarjan(int n){
            mem(vis, 0);
            mem(instack, 0);
            mem(dfn, 0);
            mem(low, 0);
            mem(scc, 0);
            id = scc_num = 0;
            for (int i = 0; i <= n; i ++)
                scc_node[i].clear();
            while(!st.empty())
                st.pop();
            for (int i = 1; i <= n; i ++){   //枚举节点
                if (!vis[i])
                    dfs(i);
            }
            return ;
        }
    }S;
    bool like[MAXN][MAXN];
    vector  girl;
    void solve(int n){
        S.tarjan(n+n);
        for (int i = 1; i <= n; i ++){
            int i_scc = S.scc[i];
            girl.clear();
            for (int j = 0; j < (int)S.scc_node[i_scc].size(); j ++){
                int node = S.scc_node[i_scc][j];
                if (node > n && like[i][node - n]){
                    girl.push_back(node - n);
                }
            }
            sort(girl.begin(), girl.end());
            printf("%d", girl.size());
            for (int j = 0; j < (int)girl.size(); j ++){
                printf(" %d", girl[j]);
            }
            puts("");
        }
    }
    int main(){
    	//freopen("test.in", "r", stdin);
    	//freopen("test.out", "w", stdout);
        int n;
        while(scanf("%d", &n) != EOF){
            S.init();
            mem(like, 0);
            for (int i = 1; i <= n; i ++){
                int num;
                scanf("%d", &num);
                for (int j = 0; j < num; j ++){
                    int girl;
                    scanf("%d", &girl);
                    S.add(i, girl + n);
                    like[i][girl] = true;
                }
            }
            for (int i = 1; i <= n; i ++){
                int girl;
                scanf("%d", &girl);
                S.add(girl+n, i);
            }
            solve(n);
        }
    	return 0;
    }
    
     
  • 相关阅读:
    <原创>engine中地块的自动编号函数
    <原创>获取窗口上RadioButton的Tag值
    <原创>SQLServer一个高效的存储过程
    ArcEngine中放大、缩小、移动等功能实现的方法
    sublime No packages available for installation
    特殊字符,英文,中文排序
    关于 js中replace 特殊符号 ‘.’ 的问题
    12.3日电话面试
    electron 打包后node_modules 体积过于庞大
    git 本地同步分支数,删除远程已经删除掉的多余分支
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114288.html
Copyright © 2011-2022 走看看