题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3182
最大点权独立集。算法是建立网络流模型,加源汇点s和t,源点s向x集合中的每个点建立边,容量为点的权值,y集合的每个点向汇t建立边,容量为点的权值,然后x集合和y集合相关联的点建立边,容量为INF。最后求最小割就可以了,所有点的权值之和减去最小割就是最大权值,独立点集就是全集减去最小割的点集。为什么是这样的呢?其实每条增广路代表的就是一条相关联的边,找到一条增广路我们就删除一个点,如果找不到增广路了,那么剩下的点就是独立的了。由于是最小割,那么删除的点集的权值就是最小的,即剩下的是最大权。这里还要求求出最小割点集,在做完最大流后在残余网络上求一次bfs就可以了,能经过的点就是S集合的,否则就是T集合的。我开始以为在bfs时只要边的容量为零,边能通过且点没有经过,那么此边就是割边,后来发现还是错了。看一个样例:
那么这里最小割显然是3-t,4-t,如果按上面方法求,就错了,因为那个没有考虑反向边,所以应该做次bfs后根据S集合和T集合判断。
1 //STATUS:C++_AC_450MS_2948KB 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<string.h> 5 #include<math.h> 6 #include<iostream> 7 #include<string> 8 #include<algorithm> 9 #include<vector> 10 #include<queue> 11 #include<stack> 12 #include<map> 13 using namespace std; 14 #define LL long long 15 #define pii pair<int,int> 16 #define Max(a,b) ((a)>(b)?(a):(b)) 17 #define Min(a,b) ((a)<(b)?(a):(b)) 18 #define mem(a,b) memset(a,b,sizeof(a)) 19 #define lson l,mid,rt<<1 20 #define rson mid+1,r,rt<<1|1 21 const int MAX=210,INF=0x3f3f3f3f; 22 const LL LLNF=0x3f3f3f3f3f3f3f3fLL; 23 24 struct Edge{ 25 int u,v,cap; 26 }e[MAX*MAX*4]; 27 28 int first[MAX],next[MAX*MAX*4],p[MAX],cur[MAX],w[MAX],num[MAX],d[MAX]; 29 int n,n1,n2,m,mt,s,t; 30 31 void adde(int a,int b,int val){ 32 e[mt].u=a,e[mt].v=b,e[mt].cap=val; 33 next[mt]=first[a],first[a]=mt++; 34 e[mt].u=b,e[mt].v=a,e[mt].cap=0; 35 next[mt]=first[b],first[b]=mt++; 36 } 37 38 int augment() 39 { 40 int x=t,a=INF; 41 while(x!=s){ 42 a=Min(a,e[p[x]].cap); 43 x=e[p[x]].u; 44 } 45 x=t; 46 while(x!=s){ 47 e[p[x]].cap-=a; 48 e[p[x]^1].cap+=a; 49 x=e[p[x]].u; 50 } 51 return a; 52 } 53 54 int isap() 55 { 56 int i,x=s,ok,flow=0,min; 57 mem(d,0);mem(num,0); 58 num[0]=t+1; 59 for(i=0;i<=t;i++)cur[i]=first[i]; 60 while(d[s]<=t){ 61 if(x==t){ 62 flow+=augment(); 63 x=s; 64 } 65 ok=0; 66 for(i=cur[x];i!=-1;i=next[i]){ 67 if(e[i].cap && d[x]==d[e[i].v]+1){ 68 ok=1; 69 p[e[i].v]=i; 70 cur[x]=i; 71 x=e[i].v; 72 break; 73 } 74 } 75 if(!ok){ 76 min=t; 77 for(i=first[x];i!=-1;i=next[i]) 78 if(e[i].cap && d[e[i].v]<min)min=d[e[i].v]; 79 if(--num[d[x]]==0)break; 80 num[d[x]=min+1]++; 81 cur[x]=first[x]; 82 if(x!=s)x=e[p[x]].u; 83 } 84 } 85 return flow; 86 } 87 88 void bfs() 89 { 90 int i,x; 91 mem(d,0); 92 queue<int> q; 93 q.push(s); 94 d[s]=1; 95 while(!q.empty()){ 96 x=q.front();q.pop(); 97 for(i=first[x];i!=-1;i=next[i]) 98 if(e[i].cap && !d[e[i].v]){ 99 d[e[i].v]=1; 100 q.push(e[i].v); 101 } 102 } 103 } 104 105 int main() 106 { 107 // freopen("in.txt","r",stdin); 108 int i,a,b,all,mincut,cou1,cou2,flag; 109 while(~scanf("%d%d%d",&n1,&n2,&m)) 110 { 111 n=n1+n2; 112 t=n+1; 113 cou1=cou2=mincut=all=s=mt=0; 114 mem(first,-1); 115 116 for(i=1;i<=n1;i++){ 117 scanf("%d",&a); 118 adde(s,i,a); 119 all+=w[i]=a; 120 } 121 for(;i<=n;i++){ 122 scanf("%d",&a); 123 adde(i,t,a); 124 all+=w[i]=a; 125 } 126 for(i=0;i<m;i++){ 127 scanf("%d%d",&a,&b); 128 adde(a,n1+b,INF); 129 } 130 131 mincut=isap(); 132 bfs(); 133 134 for(i=1;i<=n;i++) 135 if(d[i] && i<=n1)cou1++; 136 else if(!d[i] && i>n1)cou2++; 137 printf("%d %d %d\n",all-mincut,cou1,cou2); 138 for(i=1,flag=1;i<=n1;i++) 139 if(d[i]){ 140 if(flag){printf("%d",i);flag=0;} 141 else printf(" %d",i); 142 } 143 putchar('\n'); 144 for(flag=1;i<=n;i++) 145 if(!d[i]){ 146 if(flag){printf("%d",i-n1);flag=0;} 147 else printf(" %d",i-n1); 148 } 149 putchar('\n'); 150 } 151 return 0; 152 }