• hdu 4685 二分匹配+强连通分量


    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=4685

    题解:

    这一题是poj 1904的加强版,poj 1904王子和公主的人数是一样多的,并且给出了一个完美匹配,而这一题王子和公主的人数是不同的,而且没有给出任何匹配。因此借鉴1904的做法,我们可以对这题做一些预处理,从而使得它和poj 1904一样能够用强连通分量来求解。

    首先求出一个最大匹配,对于每一个没有匹配的王子,加一个虚拟的公主与之匹配,对于每一个没有匹配的公主,加一个虚拟的的王子与之匹配,这样就可以得到一个完美匹配了。并且使得所有的王子都与虚拟的公主连边,所有的公主都与每一个虚拟的王子相连

    这样建完图后就可以和poj 1904一样的做法了。

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<vector>
      5 #include<stack>
      6 #include<algorithm>
      7 using namespace std;
      8 
      9 const int maxn = 2222;
     10 
     11 int scan() {
     12     int ret = 0, flag = 0; char ch;
     13     if ((ch = getchar()) == '-') flag = 1;
     14     else if (ch >= '0'&&ch <= '9') ret = ch - '0';
     15     while ((ch = getchar()) >= '0'&&ch <= '9') ret = ret * 10 + ch - '0';
     16     return flag ? -ret : ret;
     17 }
     18 
     19 void out(int x) {
     20     if (x>9) out(x / 10);
     21     putchar(x % 10 + '0');
     22 }
     23 
     24 int _t[maxn], lef[maxn];
     25 
     26 int n, m;
     27 
     28 vector<int> G[maxn],G2[maxn];
     29 
     30 //二分图的最大匹配----------------------------------------------- 
     31 bool match(int u) {
     32     for (int i = 0; i < G[u].size(); i++) {
     33         int v = G[u][i];
     34         if (!_t[v]) {
     35             _t[v] = 1;
     36             if (lef[v]==-1 || match(lef[v])) {
     37                 lef[v] = u;
     38                 return true;
     39             }
     40         }
     41     }
     42     return false;
     43 }
     44 
     45 void BM() {
     46     for (int i = 0; i < n; i++) {
     47         memset(_t, 0, sizeof(_t));
     48         match(i);
     49     }
     50     //for (int i = 0; i < m; i++) {
     51     //    printf("lef[%d]:%d
    ", i + 1, lef[i]+1);
     52     //}
     53 }
     54 //--------------------------------------------------------------- 
     55 
     56 //tarjan求强连通---------------------------------------------- 
     57 int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;
     58 stack<int> S;
     59 
     60 void dfs(int u) {
     61     pre[u] = lowlink[u] = ++dfs_clock;
     62     S.push(u);
     63     for (int i = 0; i < G2[u].size(); i++) {
     64         int v = G2[u][i];
     65         if (!pre[v]) {
     66             dfs(v);
     67             lowlink[u] = min(lowlink[u], lowlink[v]);
     68         }
     69         else if (!sccno[v]) {
     70             lowlink[u] = min(lowlink[u], pre[v]);
     71         }
     72     }
     73     if (lowlink[u] == pre[u]) {
     74         scc_cnt++;
     75         for (;;) {
     76             int x = S.top(); S.pop();
     77             sccno[x] = scc_cnt;
     78             if (x == u) break;
     79         }
     80     }
     81 }
     82 
     83 void find_scc(int n) {
     84     dfs_clock = scc_cnt = 0;
     85     memset(sccno, 0, sizeof(sccno));
     86     memset(pre, 0, sizeof(pre));
     87     for (int i = 0; i < n; i++) {
     88         if (!pre[i]) dfs(i);
     89     }
     90 }
     91 //--------------------------------------------------------------- 
     92 
     93 
     94 int vis[maxn];
     95 void solve() {
     96     //build
     97     memset(vis, 0, sizeof(vis));
     98     int tot_n = n;
     99     //构造完美匹配----------------------- 
    100     for (int i = 0; i < m; i++) {
    101         if (lef[i] == -1) {
    102             lef[i] = tot_n++;
    103         }
    104         vis[lef[i]] = 1;
    105     }
    106     int tot_m = m;
    107     for (int i = 0; i < tot_n; i++) {
    108         if (vis[i] == 0) lef[tot_m++] = i;
    109     }
    110     //-------------------
    111     
    112     //每一个王子心仪的公主的连边 
    113     for (int i = 0; i < n; i++) {
    114         for (int j = 0; j < G[i].size(); j++) {
    115             int v = G[i][j];
    116             G2[i].push_back(v + tot_n);
    117         }
    118     }
    119     //每一个虚拟的王子与所有的公主的连边 
    120     for (int i = n; i < tot_n; i++) {
    121         for (int v = 0; v < m; v++) {
    122             G2[i].push_back(v + tot_n);
    123         }
    124     }
    125     //所有的王子与每一个虚拟公主连边 
    126     for (int i = m; i < tot_n; i++) {
    127         for (int v = 0; v < tot_n; v++) {
    128             G2[v].push_back(i+tot_n);
    129         }
    130     }
    131     //每一个公主与和她匹配的那个王子连边 
    132     for (int i = 0; i < tot_n; i++) {
    133         G2[i + tot_n].push_back(lef[i]);
    134     }
    135 
    136     //printf("tot_n:%d
    ", tot_n);
    137     //for (int i = 0; i < tot_n * 2; i++) {
    138     //    printf("%d:", i + 1);
    139     //    for (int j = 0; j < G2[i].size(); j++) {
    140     //        int v = G2[i][j]; v++;
    141     //        printf("%d ", v);
    142     //    }
    143     //    printf("
    ");
    144     //}
    145 
    146     //solve
    147     find_scc(tot_n*2);
    148 
    149     //for (int i = 0; i < tot_n * 2; i++) {
    150     //    printf("sccno[%d]:%d
    ", i + 1, sccno[i]);
    151     //}
    152 
    153     //print
    154     for (int i = 0; i < n; i++) {
    155         vector<int> ans;
    156         for (int j = 0; j < G[i].size(); j++) {
    157             int v = G[i][j];
    158             if (sccno[i] == sccno[v + tot_n]) ans.push_back(v);
    159         }
    160         sort(ans.begin(), ans.end());
    161         out(ans.size());
    162         for (int i = 0; i < ans.size(); i++) {
    163             putchar(' ');
    164             out(ans[i] + 1);
    165         }
    166         putchar('
    ');
    167     }
    168 }
    169 
    170 void init() {
    171     for (int i = 0; i < maxn; i++) G[i].clear(),G2[i].clear();
    172     memset(lef, -1, sizeof(lef));
    173 }
    174 
    175 int main() {
    176     int tc,kase=0;
    177     tc = scan();
    178     while (tc--) {
    179         init();
    180         n = scan(); m = scan();
    181         int ct,v;
    182         for (int i = 0; i < n; i++) {
    183             ct = scan();
    184             for (int j = 0; j < ct; j++) {
    185                 v = scan(); v--;
    186                 G[i].push_back(v);
    187             }
    188         }
    189         printf("Case #%d:
    ", ++kase);
    190         BM();
    191         solve();
    192     }
    193     return 0;
    194 }
  • 相关阅读:
    vsprintf解析
    带grub的软盘镜像制作
    SunnyOS准备4
    SunnyOS准备3
    SunnyOS准备1
    汇编第七日
    汇编第六日
    解决k8s集群中mount volume失败的问题
    更新k8s集群的证书
    为k8s集群配置自定义告警
  • 原文地址:https://www.cnblogs.com/fenice/p/5510777.html
Copyright © 2020-2023  润新知