HDU 5352 MZL's City (2015 Multi-University Training Contest 5)
题目大意:
一个地方的点和道路在M年前全部被破坏,每年可以有三个操作, 1.把与一个点X一个联通块内的一些点重建,2.连一条边,3.地震震坏一些边,每年最多能重建K个城市,问最多能建多少城市,并输出操作要让字典序最小
思路:
trivial:显然每年向当年可以建的城市连边,每年可以匹配最多K个城市,嗯,很明显的网络流思路,可这样方案数不太好输出
full:再仔细想想这就是多对一的多重匹配,跑一跑匈牙利就可以,K个城市可以拆点,当然简单的方法直接跑K次也可以(想一想为什么)
为了字典序最小,我们要尽量让后面的点匹配,所以从后往前跑匹配就可以
1 // i love zxr 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #define maxn 10009 6 using namespace std; 7 int matrix[209][209]; 8 int nex[maxn],head[maxn],point[maxn],now; 9 int mark[maxn],deg[maxn],ans[maxn]; 10 int visit[maxn],x,y,match[maxn],o,p,n,m,k,h 11 ; 12 void add(int x,int y) 13 { 14 nex[++now] = head[x]; 15 head[x] = now; 16 point[now] = y; 17 } 18 19 int dfs1(int k,int year) 20 { 21 visit[k]=1; 22 add(year,k); 23 for(int i=1;i<=n;i++)if(matrix[k][i]==1 && !visit[i])dfs1(i,year); 24 } 25 26 int dfs(int k) 27 { 28 for(int i=head[k];i;i=next[i]) 29 { 30 int u = point[i]; 31 if(visit[u])continue; 32 visit[u]=1; 33 if(match[u]==-1 || dfs(match[u])) 34 { 35 match[u] = k; 36 return 1; 37 } 38 } 39 return 0; 40 } 41 int main() 42 { 43 int t; 44 scanf("%d",&t); 45 while(t--) 46 { 47 h=0; 48 memset(matrix,0,sizeof(matrix)); 49 memset(head,0,sizeof(head)); 50 memset(mark,0,sizeof(mark)); 51 now=0; 52 scanf("%d%d%d",&n,&m,&k); 53 for(int i=1;i<=m;i++) 54 { 55 scanf("%d",&o); 56 if(o==1) 57 { 58 scanf("%d",&x); 59 memset(visit,0,sizeof(visit)); 60 dfs1(x,i); 61 mark[i]=1; 62 } 63 if(o==2) 64 { 65 scanf("%d%d",&x,&y); 66 matrix[x][y] = 1; 67 matrix[y][x] = 1; 68 } 69 if(o==3) 70 { 71 scanf("%d",&p); 72 for(int i=1;i<=p;i++) 73 { 74 scanf("%d%d", &x, &y); 75 matrix[x][y] = 0; 76 matrix[y][x] = 0; 77 } 78 } 79 } 80 int an=0; 81 memset(match,-1,sizeof(match)); 82 for(int i=m;i>=1;i--)if(mark[i]) 83 { 84 int u =0; 85 for(int j=1;j<=k;j++) 86 { 87 memset(visit,0,sizeof(visit)); 88 if(dfs(i))u++; 89 } 90 an+=u; 91 ans[++h]=u; 92 } 93 printf("%d\n",an); 94 for(int i=h;i>=2;i--) 95 { 96 printf("%d ",ans[i]); 97 } 98 if(h)printf("%d\n",ans[1]); 99 } 100 return 0; 101 }