zoukankan      html  css  js  c++  java
  • hdu 4685(强连通分量+二分图的完美匹配)

    传送门:Problem 4685

    https://www.cnblogs.com/violet-acmer/p/9739990.html

    参考资料:

      [1]:二分图的最大匹配、完美匹配和匈牙利算法

      [2]:http://www.cnblogs.com/frog112111/p/3387173.html

    题意:

      n个王子和m个公主,王子只能和他喜欢的公主结婚,公主可以和所有的王子结婚,输出所有王子可能的结婚对象。

      必须保证王子与任意这些对象中的一个结婚,都不会影响到剩余的王子的配对数,也就是不能让剩余的王子中突然有一个人没婚可结了。

    分析:

      这题是poj 1904的加强版,poj 1904的王子和公主数是相等的,这里可以不等,且poj 1904给出了一个初始完美匹配,但是这题就要自己求。

      所以只要求出完美匹配之后,就和poj 1904的做法就完全相同了。

      那么怎么求出完美匹配呢?一开始我用多重匹配的匈牙利算法来做,但是怎么做都不对.......看了题解才恍然大悟=_=

      先说几个坑,这题有点奇怪,就是所有王子都可以争着和同一个公主结婚,只要该王子喜欢该公主,感觉公主有点悲哀呀........

      比如:

           2 2

                1 1

                1 1

          

      输出的答案是:

            1 1  

                                1 1  

      而不是    

            1 1          

             0        

      这里就是和poj 1904有点不一样的地方,坑了我好久.........

      求完美匹配:

      先对原图用匈牙利算法做一遍二分图匹配,但是还有可能剩余一些人还没匹配,只要虚拟出一些节点来匹配剩余的点就行了。

      假设王子有剩下的,那么每个剩下的王子就连一个虚拟的公主,这个公主被所有的王子都喜欢。

      假设公主有剩下的,那么每个剩下的公主就连一个虚拟的王子,这个王子喜欢所有的公主

      这样就构成完美匹配了,接下来就是和poj 1904一样了。

    AC代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<vector>
      4 #include<cstring>
      5 #include<algorithm>
      6 using namespace std;
      7 #define pb push_back
      8 #define mem(a,b) memset(a,b,sizeof a)
      9 const int maxn=500+500+500+10;
     10 
     11 int n,m;
     12 //===========匈牙利===========
     13 struct Node
     14 {
     15     int matchM[maxn];
     16     int matchW[maxn];
     17     bool check[maxn];
     18     vector<int >edge[maxn];
     19     void Init()
     20     {
     21         mem(matchM,-1);
     22         mem(matchW,-1);
     23         for(int i=0;i < maxn;++i)
     24             edge[i].clear();
     25     }
     26     void addEdge(int u,int v){
     27         edge[u].pb(v);
     28     }
     29     bool Dfs(int u)
     30     {
     31         for(int i=0;i < edge[u].size();++i)
     32         {
     33             int to=edge[u][i];
     34             if(!check[to])
     35             {
     36                 check[to]=true;
     37                 if(matchW[to] == -1 || Dfs(matchW[to]))
     38                 {
     39                     matchW[to]=u;
     40                     matchM[u]=to;
     41                     return true;
     42                 }
     43             }
     44         }
     45         return false;
     46     }
     47     void Hungarian()
     48     {
     49         for(int i=1;i <= n;++i)
     50         {
     51             mem(check,false);
     52             Dfs(i);
     53         }
     54     }
     55 }_match;
     56 //============================
     57 //============SCC=============
     58 int scc[maxn];
     59 bool vis[maxn];
     60 vector<int >vs;
     61 vector<int >edge[maxn],redge[maxn];
     62 void addEdge(int u,int v)
     63 {
     64     edge[u].pb(v);
     65     redge[v].pb(u);
     66 }
     67 void Dfs(int u)
     68 {
     69     vis[u]=true;
     70     for(int i=0;i < edge[u].size();++i)
     71     {
     72         int to=edge[u][i];
     73         if(!vis[to])
     74             Dfs(to);
     75     }
     76     vs.pb(u);
     77 }
     78 void rDfs(int u,int sccId)
     79 {
     80     scc[u]=sccId;
     81     vis[u]=true;
     82     for(int i=0;i < redge[u].size();++i)
     83     {
     84         int to=redge[u][i];
     85         if(!vis[to])
     86             rDfs(to,sccId);
     87     }
     88 }
     89 void Scc()
     90 {
     91     mem(vis,false);
     92     vs.clear();
     93     for(int i=1;i <= n;++i)
     94         if(!vis[i])
     95             Dfs(i);
     96     mem(vis,false);
     97     int sccId=0;
     98     for(int i=vs.size()-1;i >= 0;--i)
     99     {
    100         int to=vs[i];
    101         if(!vis[to])
    102             rDfs(to,++sccId);
    103     }
    104 }
    105 //============================
    106 void Init()
    107 {
    108     _match.Init();
    109     for(int i=0;i < maxn;++i)
    110         edge[i].clear(),redge[i].clear();
    111 }
    112 int main()
    113 {
    114     int T;
    115     scanf("%d",&T);
    116     for(int kase=1;kase <= T;++kase)
    117     {
    118         Init();
    119         scanf("%d%d",&n,&m);
    120         for(int i=1;i <= n;++i)
    121         {
    122             int k;
    123             scanf("%d",&k);
    124             while(k--)
    125             {
    126                 int v;
    127                 scanf("%d",&v);
    128                 addEdge(i,v+n);
    129                 _match.addEdge(i,v+n);
    130             }
    131         }
    132         _match.Hungarian();//匈牙利算法求最大匹配
    133         int all=n+m;
    134         for(int i=1;i <= n;++i)
    135         {
    136             if(_match.matchM[i] == -1)//为剩余王子匹配虚拟公主
    137             {
    138                 all++;
    139                 for(int j=1;j <= n;++j)//所有王子都喜欢该虚拟公主
    140                     addEdge(j,all);
    141                 _match.matchM[i]=all;
    142                 _match.matchW[all]=i;
    143             }
    144         }
    145         for(int i=n+1;i <= n+m;++i)
    146         {
    147             if(_match.matchW[i] == -1)//为剩余公主匹配虚拟王子
    148             {
    149                 all++;
    150                 for(int j=n+1;j <= n+m;++j)//该虚拟王子喜欢所有公主
    151                     addEdge(all,j);
    152                 _match.matchM[all]=i;
    153                 _match.matchW[i]=all;
    154             }
    155         }
    156         for(int i=1;i <= all;++i)
    157             if(_match.matchM[i] != -1)//所有与王子匹配的公主建一条边连向王子
    158                 addEdge(_match.matchM[i],i);
    159         Scc();//求强连通分量
    160         printf("Case #%d:
    ",kase);
    161         for(int i=1;i <= n;++i)
    162         {
    163             int res=0;
    164             int ans[maxn];
    165             for(int j=0;j < edge[i].size();++j)
    166             {
    167                 int to=edge[i][j];
    168                 if(scc[i] == scc[to] && to <= m+n)//剔除掉虚拟的公主
    169                     ans[res++]=to-n;
    170             }
    171             sort(ans,ans+res);
    172             printf("%d",res);
    173             for(int i=0;i < res;++i)
    174                 printf(" %d",ans[i]);
    175             printf("
    ");
    176         }
    177     }
    178 }
    Kosaraju算法
  • 相关阅读:
    grep命令详解
    Git命令详解(一)-个人使用
    android intent和intent action大全
    android 监控EditText的变化
    第86章、系统服务之TELEPHONY_SERVICE(从零开始学Android)
    android中getSystemService详解
    关于android各种双卡手机获取imei,imsi的处置(mtk,展讯,高通等)
    Android 获取运营商信息(完整版)-解决高通,MTK等双卡问题
    Android 移动缩放的ImageView
    Android 读写SD卡的文件
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/9742580.html
Copyright © 2011-2022 走看看