●POJ 2125 Destroying The Graph

题链:

http://poj.org/problem?id=2125

题解:

最小割 + 输出割方案。
建图:
拆点,每个题拆为 i 和 i'分别表示其的入点和出点
建立超源 S和超汇 T。
S -> i :(outi[i]) 割了这个边相当于选择了 i-
i'-> T :(ini[i])  割了这个边相当于选择了 i+
u -> v':(INF)
然后求Dinic跑最大流求最小割。

至于求方案,首先显然割的边都和 S或 T相连。
从 S开始沿着非满载的边(包括反向边)dfs,对遇到的点打标记。
如果某个入点 i 没有被标记过,则输出 i -
如果某个出点 i'被标记过,则输出 i +

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 500
#define MAXM 150000
#define INF 0x3f3f3f3f
using namespace std;
struct Edge{
	int to[MAXM],cap[MAXM],nxt[MAXM],head[MAXN],ent;
	void Init(){
		ent=2;
		memset(head,0,sizeof(head));
	}
	void Adde(int u,int v,int w){
		to[ent]=v; cap[ent]=w; nxt[ent]=head[u]; head[u]=ent++;
		to[ent]=u; cap[ent]=0; nxt[ent]=head[v]; head[v]=ent++;
	}
	int Next(int i,bool type){
		return type?head[i]:nxt[i];
	}
}E;
int cur[MAXN],d[MAXN],mark[MAXN];
int N,M,S,T;
int idx(int i,int k){
	return i+k*N;
}
bool bfs(){
	queue<int>q;
	memset(d,0,sizeof(d));
	d[S]=1; q.push(S); int u,v;
	while(!q.empty()){
		u=q.front(); q.pop();
		for(int i=E.Next(u,1);i;i=E.Next(i,0)){
			v=E.to[i];
			if(d[v]||!E.cap[i]) continue;
			d[v]=d[u]+1; q.push(v);
		}
	}
	return d[T];
}
int dfs(int u,int reflow){
	if(u==T||!reflow) return reflow;
	int flowout=0,f,v;
	for(int &i=cur[u];i;i=E.Next(i,0)){
		v=E.to[i];
		if(d[v]!=d[u]+1) continue;
		f=dfs(v,min(reflow,E.cap[i]));
		flowout+=f; E.cap[i^1]+=f;
		reflow-=f;	E.cap[i]-=f;
		if(!reflow) break;
	}
	if(!flowout) d[u]=0;
	return flowout;
}
int Dinic(){
	int flow=0;
	while(bfs()){
		memcpy(cur,E.head,sizeof(E.head));
		flow+=dfs(S,INF);
	}
	return flow;
}
void DFS(int u){
	mark[u]=1;
	for(int i=E.Next(u,1);i;i=E.Next(i,0)){
		if(!E.cap[i]||mark[E.to[i]]) continue;
		DFS(E.to[i]);
	}
}
int main()
{
	while(~scanf("%d%d",&N,&M)){
		memset(mark,0,sizeof(mark));
		S=2*N+1; T=2*N+2; E.Init();
		for(int i=1,x;i<=N;i++)
			scanf("%d",&x),E.Adde(idx(i,1),T,x);
		for(int i=1,x;i<=N;i++)
			scanf("%d",&x),E.Adde(S,idx(i,0),x);
		for(int i=1,u,v;i<=M;i++)
			scanf("%d%d",&u,&v),E.Adde(idx(u,0),idx(v,1),INF);
		int ans=Dinic(),num=0;
		printf("%d\n",ans); 
		DFS(S);
		for(int i=1;i<=N;i++)  
            num+=((!mark[i])+(mark[i+N]));  
		printf("%d\n",num);
		for(int i=1;i<=N;i++)  {  
            if(!mark[i])printf("%d -\n",i);  
            if(mark[i+N])printf("%d +\n",i);  
        }
	}
	return 0;
}

posted @ 2017-11-30 20:06  *ZJ  阅读(127)  评论(0编辑  收藏  举报