poj 2125(最小割)

题目链接: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一张图:

poj 2125(最小割)

  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

 

 

你可能感兴趣的:(poj)