• 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;
    }
    
     
  • 相关阅读:
    OpenCV-Python图形图像处理:利用黑帽去除图像浅色水印
    单片机实验四:定时器控制发光二极管的亮灭+简单输出连续矩形脉冲
    实验5 linux网络编程
    第十六届全国大学智能汽车竞赛竞速比赛规则-讨论稿
    写给自己的TypeScript 入门小纲
    写给自己的TypeScript 入门小纲
    Node.js自学笔记之回调函数
    Node.js自学笔记之回调函数
    来简书坚持一个月日更之后
    全选或者单选checkbox的值动态添加到div
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114073.html
Copyright © 2020-2023  润新知