Hdu 5352 MZL's City (多重匹配)

题目链接:

  Hdu 5352 MZL's City

题目描述:

  有n各节点,m个操作。刚开始的时候节点都是相互独立的,一共有三种操作:

  1:把所有和x在一个连通块内的未重建过的点全部重建。

  2:建立一条双向路(x,y)

  3:又发生了地震,p条路被毁。

  问最后最多有多少个节点被重建,输出重建节点的最小字典序。

解题思路:

  这几天正好在学匹配,但是昨天下午还是没有看出来这个是匹配题目。看了题解扪心自问了自己三次,是不是傻。就是把每个需要重建的节点x拆成k个点,然后对每个拆分后的点和与拆点在同一连通块里面的点建边,然后按照倒序进行匹配,保证字典序最大。

  但是匹配好像要比网络流慢好多,改天还是去学一下新姿势的好。

  1 #include <vector>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 using namespace std;
  7 const int maxn = 205;
  8 const int N = 205*500;
  9 vector <int> G[N];
 10 int ans[maxn*2], p[maxn], used[maxn], vis[maxn];
 11 int n, m, k, num, nu, maps[maxn][maxn];
 12 void dfs (int u)
 13 {//求连通块内的点
 14     vis[u] = 1;
 15     p[num ++] = u;
 16     for (int i=1; i<=n; i++)
 17         if (!vis[i] && maps[u][i])
 18             dfs (i);
 19 }
 20 bool Find (int u)
 21 {
 22     for (int i=0; i<G[u].size(); i++)
 23     {
 24         int v = G[u][i];
 25         if (!vis[v])
 26         {
 27             vis[v] = 1;
 28             if (!used[v] || Find(used[v]))
 29             {
 30                 used[v] = u;
 31                 return true;
 32             }
 33         }
 34     }
 35     return false;
 36 }
 37 int hungry ()
 38 {
 39     int res = 0;
 40     memset (used, 0, sizeof(used));
 41     for (int i=nu-1; i>=0; i--)//倒序求最大匹配
 42         for (int j=i*k; j<(i+1)*k; j++)
 43         {
 44             memset (vis, 0, sizeof(vis));
 45             if (Find(j))
 46             {
 47                 res ++;
 48                 ans[i] ++;
 49             }
 50         }
 51     return res;
 52 }
 53 int main ()
 54 {
 55     int t;
 56     scanf ("%d", &t);
 57     while (t --)
 58     {
 59         scanf ("%d %d %d", &n, &m, &k);
 60         memset (maps, 0, sizeof(maps));
 61         for (int i=0; i<N; i++)
 62             G[i].clear();
 63         nu = 0;
 64         while (m --)
 65         {
 66             int type, x, y, z;
 67             scanf ("%d", &type);
 68             if (type == 1)
 69             {
 70                 scanf ("%d", &x);
 71                 num = 0;
 72                 memset (vis, 0, sizeof(vis));
 73                 dfs (x);
 74                 for (int i=0; i<num; i++)//建边
 75                     for (int j=nu*k; j<(nu+1)*k; j++)//拆点
 76                         G[j].push_back(p[i]);
 77                 nu ++;
 78             }
 79             else if (type == 2)
 80             {
 81                 scanf ("%d %d", &x, &y);
 82                 maps[x][y] = maps[y][x] = 1;
 83             }
 84             else
 85             {
 86                 scanf ("%d", &z);
 87                 while (z --)
 88                 {
 89                     scanf ("%d %d", &x, &y);
 90                     maps[x][y] = maps[y][x] = 0;
 91                 }
 92             }
 93         }
 94         memset (ans, 0, sizeof(ans));
 95         int res = hungry ();
 96         printf ("%d\n", res);
 97         for (int i=0; i<nu; i++)
 98             printf ("%d%c", ans[i], i==nu-1?'\n':' ');
 99     }
100     return 0;
101 }

 

posted @ 2015-08-05 16:56  罗茜  阅读(413)  评论(2编辑  收藏  举报