这个题写了一天,现在才过......
一开始想到了二分图的最大匹配,每种组合连边,算出最多的。结果仔细一想是错的,因为没有考虑到一个牛只能选一组。
然后就想到开始建图跑最大流了,一开始采用了 源点-->牛-->食物in-->食物out-->饮料-->汇点 这样的模式建图。结果一直WA,看了Discuss,发现是错的。
拆食物错的原因在于: 如果拆食物,按照牛->食物-in->食物-out->饮料 这样建图的话,虽然保证了流量的限制,每头牛也只能选一种食物和饮料。 但是食物-out->饮料之间的边就失去的牛的编号性,就成了没有针对哪头牛的组合,不知道某些边是哪些牛的喜好。 这样就会导致某头牛明明不喜欢某种搭配,但是因为有其他牛喜欢这种搭配,使得这头牛“强行”被选择了这种搭配。自然就WA了。
然后就只能用 源点-->食物-->牛in-->牛out-->饮料--汇点 这样的模式建图。
恶心的是,刘汝佳白书的Dinic居然TLE了... ...然后找了个非递归的Dinic AC了。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; const int maxn=1000; const int inf=1<<20; //******************************************// struct Node { int v,next; int val; }edge[maxn*maxn*2]; int level[maxn];//顶点的层次 int head[maxn]; int que[maxn*10];//BFS中用于遍历的顶点,DFS求增广中记录边 int out[10*maxn];//DFS用于几乎定点的分支 int ind; void init() { ind=0; memset(head,-1,sizeof(head)); } void addedge(int x,int y,int z) { edge[ind].v=y; edge[ind].val=z; edge[ind].next=head[x]; head[x]=ind++; edge[ind].v=x; edge[ind].val=0; edge[ind].next=head[y]; head[y]=ind++; } int dinic(int n,int source,int sink) { int ret=0; int h=0,r=0; while(1)//DFS { int i; for(i=0;i<=n;++i) level[i]=0; h=0,r=0; level[source]=1; que[0]=source; while(h<=r)//BFS { int t=que[h++]; for(i=head[t];i!=-1;i=edge[i].next) { if(edge[i].val&&level[edge[i].v]==0) { level[edge[i].v]=level[t]+1; que[++r]=edge[i].v; } } } if(level[sink]==0)break;//找不到汇点 for(i=0;i<=n;++i) out[i]=head[i]; int q=-1; while(1) { if(q<0) { int cur=out[source]; for(;cur!=-1;cur=edge[cur].next) { if(edge[cur].val&&out[edge[cur].v]!=-1&&level[edge[cur].v]==2) { break; } } if(cur>=0) { que[++q]=cur; out[source]=edge[cur].next; } else break; } int u=edge[que[q]].v; if(u==sink)//一条增广路 { int dd=inf; int index=-1; for(i=0;i<=q;i++) { if(dd>edge[que[i]].val) { dd=edge[que[i]].val; index=i; } } ret+=dd; for(i=0;i<=q;i++) { edge[que[i]].val-=dd; edge[que[i]^1].val+=dd; } for(i=0;i<=q;i++) { if(edge[que[i]].val==0) { q=index-1; break; } } } else { int cur=out[u]; for(;cur!=-1;cur=edge[cur].next) { if(edge[cur].val&&out[edge[cur].v]!=-1&&level[u]+1==level[edge[cur].v]) { break; } } if(cur!=-1) { que[++q]=cur; out[u]=edge[cur].next; } else { out[u]=-1; q--; } } } } return ret; } int N,F,D,ff,dd; int FF[maxn],DD[maxn]; //输入输出 int main() { while(~scanf("%d%d%d", &N, &F, &D)) { init(); // s=0; // t=2*N+F+D+1; for(int i=2*N+1;i<=2*N+F;i++) addedge(0,i,1); for(int i=2*N+1+F;i<=2*N+F+D;i++) addedge(i,2*N+F+D+1,1); for(int i=1;i<=N;i++) addedge(i,i+N,1); for(int i=1;i<=N;i++) { scanf("%d%d",&ff,&dd); for(int j=1;j<=ff;j++) scanf("%d",&FF[j]); for(int j=1;j<=dd;j++) scanf("%d",&DD[j]); for(int j=1;j<=ff;j++) for(int k=1;k<=dd;k++) { addedge(2*N+FF[j],i,1); addedge(i+N,2*N+F+DD[k],1); } } printf("%d ",dinic(2*N+F+D+10,0,2*N+F+D+1)); } return 0; }