最小点权覆盖集的总权值 + 最大点权独立集的总权值 = 图的总权值
所以最大点权独立集的题目都可以转换成最小点权覆盖集的题目
注意:图必须是二分图 否则是NP问题
两道典型的题目
最大点权独立集
hdu 1565 http://acm.hdu.edu.cn/showproblem.php?pid=1565
将方格黑白染色(类似于国际象棋的棋盘),然后出现二分图了,怎么建边?代码已经很详细了
#include<stdio.h> #include<string.h> const int MAX=1010; const int INF=1000000000; struct{ int v,c,next; }edge[100000]; int E,head[MAX]; int gap[MAX],cur[MAX]; int pre[MAX],dis[MAX]; void add_edge(int s,int t,int c,int cc) { /*加边的时候同时加两条, 一条正的,一条反的, 一般情况下反的容量是0 */ edge[E].v=t; edge[E].c=c; edge[E].next=head[s]; head[s]=E++; edge[E].v=s; edge[E].c=cc; edge[E].next=head[t]; head[t]=E++; } int min(int a,int b){return (a==-1||b<a)?b:a;} int SAP(int s,int t,int n){ memset(gap,0,sizeof(gap)); memset(dis,0,sizeof(dis)); int i; for(i=0;i<n;i++)cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1,v; gap[0]=n; while(dis[s]<n){ loop: for(i=cur[u];i!=-1;i=edge[i].next){ v=edge[i].v; if(edge[i].c>0&&dis[u]==dis[v]+1){ aug=min(aug,edge[i].c); pre[v]=u; cur[u]=i; u=v; if(u==t){ for(u=pre[u];v!=s;v=u,u=pre[u]){ edge[cur[u]].c-=aug; edge[cur[u]^1].c+=aug; } maxflow+=aug; aug=-1; } goto loop; } } int mindis=n; for(i=head[u];i!=-1;i=edge[i].next){ v=edge[i].v; if(edge[i].c>0&&dis[v]<mindis){ cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0)break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } int n; int ID(int x,int y){ return (x-1)*n+y; } int main() { while(scanf("%d",&n)!=EOF) { int w; memset(head,-1,sizeof(head)); E=0; int S=0,T=n*n+1; int sum=0; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&w); sum+=w; if((i+j)%2==0){ add_edge(S,ID(i,j),w,0); if(i<n) { add_edge(ID(i,j),ID(i+1,j),INF,0); } if(j<n) { add_edge(ID(i,j),ID(i,j+1),INF,0); } if(i>1) { add_edge(ID(i,j),ID(i-1,j),INF,0); } if(j>1) { add_edge(ID(i,j),ID(i,j-1),INF,0); } } else { add_edge(ID(i,j),T,w,0); } } } int tmp=SAP(S,T,T+1); printf("%d\n",sum-tmp); } return 0; }
最小点权覆盖集
http://www.cnblogs.com/wuyiqi/archive/2012/03/13/2393481.html
最大点权独立集 zoj 3165 (输出解,基本和上题一样,最小点覆盖的补图就是最大点独立集)
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int MAX=250; const int INF=1000000000; struct{ int v,c,next; }edge[20000]; int E,head[MAX]; int gap[MAX],cur[MAX]; int pre[MAX],dis[MAX]; void add_edge(int s,int t,int c,int cc) { /*加边的时候同时加两条, 一条正的,一条反的, 一般情况下反的容量是0 */ edge[E].v=t; edge[E].c=c; edge[E].next=head[s]; head[s]=E++; edge[E].v=s; edge[E].c=cc; edge[E].next=head[t]; head[t]=E++; } int min(int a,int b){return (a==-1||b<a)?b:a;} int SAP(int s,int t,int n){ memset(gap,0,sizeof(gap)); memset(dis,0,sizeof(dis)); int i; for(i=0;i<n;i++)cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1,v; gap[0]=n; while(dis[s]<n){ loop: for(i=cur[u];i!=-1;i=edge[i].next){ v=edge[i].v; if(edge[i].c>0&&dis[u]==dis[v]+1){ aug=min(aug,edge[i].c); pre[v]=u; cur[u]=i; u=v; if(u==t){ for(u=pre[u];v!=s;v=u,u=pre[u]){ edge[cur[u]].c-=aug; edge[cur[u]^1].c+=aug; } maxflow+=aug; aug=-1; } goto loop; } } int mindis=n; for(i=head[u];i!=-1;i=edge[i].next){ v=edge[i].v; if(edge[i].c>0&&dis[v]<mindis){ cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0)break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } int n,m; int A,B; bool flag[MAX]; void dfs(int s){ flag[s]=true;//printf("s=%d\n",s); for(int i=head[s];i!=-1;i=edge[i].next){ int v=edge[i].v; if(!flag[v] && edge[i].c){ dfs(v); } } } int main() { int s; while(scanf("%d%d%d",&m,&n,&s)!=EOF) { int w; memset(head,-1,sizeof(head)); E=0;A=0;B=0; int S=0,T=m+n+1; int sum=0; for(int i=1;i<=m;i++) { scanf("%d",&w); sum+=w; add_edge(S,i,w,0); } for(int i=1;i<=n;i++) { scanf("%d",&w); sum+=w; add_edge(m+i,T,w,0); } int a,b; for(int i=0;i<s;i++) { scanf("%d%d",&a,&b); add_edge(a,m+b,INF,0); } int max_flow=SAP(S,T,T+1); int ans=sum-max_flow; memset(flag,false,sizeof(flag)); dfs(S); for(int i=1;i<=m;i++) { if(flag[i]) A++; } for(int i=1;i<=n;i++) { if(!flag[i+m]) B++; } int f=0; printf("%d %d %d\n",ans,A,B); for(int i=1;i<=m;i++) { if(flag[i]) { if(!f) { f=1; printf("%d",i); } else { printf(" %d",i); } } } puts(""); f=0; for(int i=1;i<=n;i++) { if(!flag[i+m]) { if(!f) { f=1; printf("%d",i); } else { printf(" %d",i); } } } puts(""); } return 0; }