poj 2125(最小割)

来源:互联网 发布:mac php protobuf 编辑:程序博客网 时间:2024/05/18 01:22

题目链接:http://poj.org/problem?id=2125

思路:将最小点权覆盖转化为最小割模型,于是拆点建图,将点i拆成i,i+n,其中vs与i相连,边容量为w[i]-,i+n与vt相连,边容量为w[i]+,如果i,j有边相连,则i与j+n连边inf.从而跑最大流求解。对于输出解决放案,我们可以在残余网络中进行dfs,从vs出发,对于那些i<=n没有遍历到的点,说明被取走了,输出‘-’,对于那些i>n遍历到的点,说明之前有j->i的边(j<=n),vs->j不是最小割中的边,i是最小割中的点,输出‘+’。

copy一张图:

  1 #include<iostream>  2 #include<cstdio>  3 #include<cstring>  4 #include<algorithm>  5 #include<queue>  6 using namespace std;  7 #define MAXN 222  8 #define MAXM 2222222  9 #define inf 1<<30 10  11 struct Edge{ 12     int v,cap,next; 13 }edge[MAXM]; 14  15 int n,m,NE,vs,vt,NV; 16 int head[MAXN]; 17  18 void Insert(int u,int v,int cap) 19 { 20     edge[NE].v=v; 21     edge[NE].cap=cap; 22     edge[NE].next=head[u]; 23     head[u]=NE++; 24  25     edge[NE].v=u; 26     edge[NE].cap=0; 27     edge[NE].next=head[v]; 28     head[v]=NE++; 29 } 30  31 int from[MAXN],to[MAXN]; 32 bool map[MAXN][MAXN]; 33  34 void Build() 35 { 36     NE=0; 37     memset(head,-1,sizeof(head)); 38     vs=0,vt=2*n+1,NV=2*n+2; 39     for(int i=1;i<=n;i++){ 40         Insert(vs,i,to[i]); 41         Insert(i+n,vt,from[i]); 42         for(int j=1;j<=n;j++){ 43             if(map[i][j])Insert(i,j+n,inf); 44         } 45     } 46 } 47  48 int level[MAXN],gap[MAXN]; 49 void bfs(int vt) 50 { 51     memset(level,-1,sizeof(level)); 52     memset(gap,0,sizeof(gap)); 53     level[vt]=0; 54     gap[level[vt]]++; 55     queue<int>que; 56     que.push(vt); 57     while(!que.empty()){ 58         int u=que.front(); 59         que.pop(); 60         for(int i=head[u];i!=-1;i=edge[i].next){ 61             int v=edge[i].v; 62             if(level[v]<0){ 63                 level[v]=level[u]+1; 64                 gap[level[v]]++; 65                 que.push(v); 66             } 67         } 68     } 69 } 70  71 int cur[MAXN],pre[MAXN]; 72  73 int SAP(int vs,int vt) 74 { 75     bfs(vt); 76     memset(pre,-1,sizeof(pre)); 77     memcpy(cur,head,sizeof(head)); 78     int maxflow=0,aug=inf; 79     int u=pre[vs]=vs; 80     gap[0]=NV; 81     while(level[vs]<NV){ 82         bool flag=false; 83         for(int &i=cur[u];i!=-1;i=edge[i].next){ 84             int v=edge[i].v; 85             if(edge[i].cap>0&&level[u]==level[v]+1){ 86                 flag=true; 87                 pre[v]=u; 88                 u=v; 89                 aug=min(aug,edge[i].cap); 90                 if(v==vt){ 91                     maxflow+=aug; 92                     for(u=pre[v];v!=vs;v=u,u=pre[u]){ 93                         edge[cur[u]].cap-=aug; 94                         edge[cur[u]^1].cap+=aug; 95                     } 96                     aug=inf; 97                 } 98                 break; 99             }100         }101         if(flag)continue;102         int minlevel=NV;103         for(int i=head[u];i!=-1;i=edge[i].next){104             int v=edge[i].v;105             if(edge[i].cap>0&&level[v]<minlevel){106                 minlevel=level[v];107                 cur[u]=i;108             }109         }110         if(--gap[level[u]]==0)break;111         level[u]=minlevel+1;112         gap[level[u]]++;113         u=pre[u];114     }115     return maxflow;116 }117 118 bool mark[MAXN];119 void dfs(int u)120 {121     mark[u]=true;122     for(int i=head[u];i!=-1;i=edge[i].next){123         int v=edge[i].v;124         if(!mark[v]&&edge[i].cap>0)dfs(v);125     }126 }127 128 129 int main()130 {131 //   freopen("1.txt","r",stdin);132     int u,v,cnt;133     while(~scanf("%d%d",&n,&m)){134         for(int i=1;i<=n;i++)scanf("%d",&from[i]);135         for(int i=1;i<=n;i++)scanf("%d",&to[i]);136         memset(map,false,sizeof(map));137         while(m--){138             scanf("%d%d",&u,&v);139             map[u][v]=true;140         }141         Build();142         printf("%d\n",SAP(vs,vt));143         memset(mark,false,sizeof(mark));144         dfs(vs);145         cnt=0;146         for(int i=1;i<=2*n;i++){147             if(!mark[i]&&i<=n)cnt++;148             else if(mark[i]&&i>n)cnt++;149         }150         printf("%d\n",cnt);151         for(int i=1;i<=2*n;i++){152             if(!mark[i]&&i<=n)printf("%d -\n",i);153             else if(mark[i]&&i>n)printf("%d +\n",i-n);154         }155     }156     return 0;157 }
View Code

 

 

0 0
原创粉丝点击