题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=33631
【思路】
最大流。
构图:
1 建立m个x点表示贴纸,n-1个y点表示Bob的朋友,ST表示源汇点。
2 S向x[j]连一条容量为sum[0][j]的边,表示Bob可以换出如是贴纸。
3 y[j]向x[i]连容量为1的边当且仅当i没有j,x[i]向y[j]连容量为sum[i][j]-1的边。
4 x[i]向T连一条容量为1的边统计不同种类的数目。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<vector> 5 using namespace std; 6 7 const int maxn = 100+10; 8 const int INF = 1e9; 9 10 struct Edge{ 11 int u,v,cap,flow; 12 }; 13 struct Dinic { 14 int n,m,s,t; 15 bool vis[maxn]; 16 int d[maxn],cur[maxn]; 17 vector<int> G[maxn]; 18 vector<Edge> es; 19 20 void init(int n) { 21 this->n=n; 22 es.clear(); 23 for(int i=0;i<n;i++) G[i].clear(); 24 } 25 void AddEdge(int u,int v,int cap) { 26 es.push_back((Edge){u,v,cap,0}); 27 es.push_back((Edge){v,u,0,0}); 28 m=es.size(); 29 G[u].push_back(m-2); 30 G[v].push_back(m-1); 31 } 32 33 bool BFS() { 34 queue<int> q; 35 memset(vis,0,sizeof(vis)); 36 q.push(s); vis[s]=1; d[s]=0; 37 while(!q.empty()) { 38 int u=q.front(); q.pop(); 39 for(int i=0;i<G[u].size();i++) { 40 Edge& e=es[G[u][i]]; 41 int v=e.v; 42 if(!vis[v] && e.cap>e.flow) { 43 vis[v]=1; 44 d[v]=d[u]+1; 45 q.push(v); 46 } 47 } 48 } 49 return vis[t]; 50 } 51 int DFS(int u,int a) { 52 if(u==t || a==0) return a; 53 int flow=0,f; 54 for(int& i=cur[u];i<G[u].size();i++){ 55 Edge& e=es[G[u][i]]; 56 int v=e.v; 57 if( d[v]==d[u]+1 && (f=DFS(v,min(a,e.cap-e.flow)))>0 ) { 58 e.flow+=f; 59 es[G[u][i]^1].flow-=f; 60 flow+=f,a-=f; 61 if(!a) break; 62 } 63 } 64 return flow; 65 } 66 int Maxflow(int s,int t) { 67 this->s=s , this->t=t; 68 int flow=0; 69 while(BFS()) { 70 memset(cur,0,sizeof(cur)); 71 flow+=DFS(s,INF); 72 } 73 return flow; 74 } 75 }dinic; 76 77 int T,n,m; 78 int sum[maxn][maxn]; 79 80 int main() { 81 scanf("%d",&T); 82 int kase=0; 83 while(T--) { 84 scanf("%d%d",&n,&m); 85 dinic.init(n+m+1); 86 memset(sum,0,sizeof(sum)); 87 int a,b; 88 for(int i=0;i<n;i++) { 89 scanf("%d",&a); 90 for(int j=0;j<a;j++){ 91 scanf("%d",&b); 92 sum[i][b-1]++; 93 } 94 } 95 int s=n+m-1,t=n+m; 96 for(int i=0;i<m;i++) { 97 if(sum[0][i]) dinic.AddEdge(s,i,sum[0][i]); 98 dinic.AddEdge(i,t,1); 99 } 100 for(int i=0;i<n;i++) 101 for(int j=0;j<m;j++) { 102 if(!sum[i][j]) dinic.AddEdge(j,i+m-1,1); 103 if(sum[i][j]>1) dinic.AddEdge(i+m-1,j,sum[i][j]-1); 104 } 105 printf("Case #%d: %d\n",++kase,dinic.Maxflow(s,t)); 106 } 107 return 0; 108 }
时间: 2024-10-04 11:47:11