贴一张图
关于对问题的转化:
当两个人交换收藏品时,显然我们进行这个操作是为了得到更优解。
那么一个收藏品是有用的,另一个被换走的收藏品可以当做直接扔掉了。
所以只要保留一个就可以了。
注意边数、点数要开够
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 #define N 20010 7 int min(int a,int b){return a<b?a:b;} 8 int n,m,u,S,T,val[N],d[N],cur[N],fir[N]; bool vis[N]; 9 int cnt,hd[N],nxt[N<<1],ed[N],poi[N<<1]; 10 int cap[N<<1],flow[N<<1],ans; 11 queue <int> h; 12 void adde(int x,int y,int v1,int v2){ 13 nxt[ed[x]]=++cnt; hd[x]=hd[x]?hd[x]:cnt; 14 ed[x]=cnt; poi[cnt]=y; flow[cnt]=v1; cap[cnt]=v2; 15 } 16 #define to poi[i] 17 bool bfs(){ 18 memset(vis,0,sizeof(vis)); 19 h.push(S); vis[S]=1; d[S]=0; 20 while(!h.empty()){ 21 int x=h.front(); h.pop(); 22 for(int i=hd[x];i;i=nxt[i]) 23 if(!vis[to]&&cap[i]>flow[i]){ 24 vis[to]=1; d[to]=d[x]+1; 25 h.push(to); 26 } 27 }return vis[T]; 28 } 29 int dinic(int x,int a){ 30 if(!a||x==T) return a; 31 int F=0,f; 32 for(int &i=cur[x];i&&a;i=nxt[i]) 33 if(d[to]==d[x]+1&&(f=dinic(to,min(a,cap[i]-flow[i])))>0){ 34 F+=f; flow[i]+=f; 35 a-=f; flow[i^1]-=f; 36 } 37 return F; 38 } 39 void nect(int x,int y,int v){adde(x,y,0,v);adde(y,x,0,0);}//一条边以及它的反向边 40 int main(){ 41 int TuT;scanf("%d",&TuT); 42 while(TuT--){ 43 memset(hd,0,sizeof(hd)); 44 memset(nxt,0,sizeof(nxt)); 45 memset(ed,0,sizeof(ed));cnt=1; 46 scanf("%d%d",&n,&m); 47 S=1;T=u=2;ans=0; 48 for(int i=1;i<=n;++i){ 49 scanf("%d",&val[i]); 50 nect(S,++u,1);fir[i]=u; 51 } 52 for(int i=1,q1,q2;i<=m;++i){ 53 scanf("%d%d",&q1,&q2); 54 nect(fir[q1],++u,val[q1]);fir[q1]=u; 55 nect(fir[q2],++u,val[q2]);fir[q2]=u; 56 nect(fir[q1],fir[q2],1); 57 nect(fir[q2],fir[q1],1); 58 }nect(fir[1],T,val[1]); 59 while(bfs()){//普通dinic 60 for(int i=1;i<=u;++i) cur[i]=hd[i]; 61 ans+=dinic(S,2e9); 62 }printf("%d ",ans); 63 }return 0; 64 }