from:neopenxios
題目大意:Bob有一些貼紙,他能夠和別人交換,他能夠把本身獨有的貼紙拿出去,也能夠把重複的貼紙拿出去(有時候把獨有的貼紙而不是重複的貼紙拿出去能換到更多貼紙)。網絡
Bob的朋友也有一些貼紙,可是他們只會拿本身重複的貼紙和Bob換,並且換的是本身沒有的貼紙。spa
求Bob最後最多能有多少種貼紙。code
解題思路:blog
題目意思很明確了。就算把重複的貼紙拿出去也不必定最優,貪心就不用嘗試了。資源
全局資源調配得使用網絡流模型。get
建圖方式:string
①S點(看做是Bob)->全部物品:連一條邊,cap是Bob持有貼紙數量。io
②:全部朋友->全部物品:若是這我的持有的該貼紙數量>=2,連一條邊,cap是貼紙數量-1。(緣由是這些人只會把重複的貼紙拿出去)。class
③:全部物品->全部朋友:若是這我的沒有改物品,連一條邊,cap=1,。(緣由是這些人會接受本身沒有的貼紙)
④:全部物品->T點:連一條邊,cap=1,統計物品的種類。
這樣建圖以後,全部物品能夠看做Bob的總資產,這個總資產能夠流進,也能夠流出,在這基礎上作一次最大流,就是結果了。
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int N=700; struct edge{int v,next,cap;}e[N<<1];int tot=1,head[N]; int n,m,cas,Cas,S,T,dis[N],q[N],a[11][26]; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void add(int x,int y,int z){ e[++tot].v=y;e[tot].cap=z;e[tot].next=head[x];head[x]=tot; e[++tot].v=x;e[tot].cap=0;e[tot].next=head[y];head[y]=tot; } inline bool bfs(){ for(int i=S;i<=T;i++) dis[i]=-1; int h=0,t=1;q[t]=S;dis[S]=0; while(h!=t){ int x=q[++h]; for(int i=head[x];i;i=e[i].next){ if(e[i].cap&&dis[e[i].v]==-1){ dis[e[i].v]=dis[x]+1; if(e[i].v==T) return 1; q[++t]=e[i].v; } } } return 0; } int dfs(int x,int f){ if(x==T) return f; int used=0,t; for(int i=head[x];i;i=e[i].next){ if(e[i].cap&&dis[e[i].v]==dis[x]+1){ t=dfs(e[i].v,min(e[i].cap,f)); e[i].cap-=t;e[i^1].cap+=t; used+=t;f-=t; if(!f) return used; } } if(!used) dis[x]=-1; return used; } inline int dinic(){ int res=0; while(bfs()) res+=dfs(S,2e9); return res; } int main(){ cas=read(); while(cas--){ tot=1;memset(a,0,sizeof a); memset(head,0,sizeof head); n=read();m=read(); for(int i=1,k,x;i<=n;i++){ k=read(); while(k--){ x=read(); a[i][x]++; } } S=0;T=n+m+1; for(int i=1;i<=m;i++){ add(S,i,a[1][i]); add(i,T,1); } for(int i=2;i<=n;i++){ for(int j=1;j<=m;j++){ if(a[i][j]>=2) add(i+m,j,a[i][j]-1); if(!a[i][j]) add(j,i+m,1); } } printf("Case #%d: %d\n",++Cas,dinic()); } return 0; }