poj2125:Destroying The Graph(网络流)

Destroying The Graph

Time Limit: 2000MS

 

Memory Limit: 65536K

Total Submissions: 8252

 

Accepted: 2659

 

Special Judge

Description

Alice and Bob play the following game. First, Alice draws some directedgraph with N vertices and M arcs. After that Bob tries to destroy it. In a movehe may take any vertex of the graph and remove either all arcs incoming intothis vertex, or all arcs outgoing from this vertex.
Alice assigns two costs to each vertex: Wi+ and Wi-.If Bob removes all arcs incoming into the i-th vertex he pays Wi+dollars to Alice, and if he removes outgoingarcs he pays Wi-dollars.
Find out what minimal sum Bob needs to remove all arcs from the graph.

Input

Input file describes the graph Alice has drawn. The first line of the inputfile contains N and M (1 <= N <= 100, 1 <= M <= 5000). The secondline contains N integer numbers specifying Wi+. The third line defines Wi- in asimilar way. All costs are positive and do not exceed 106 . Each ofthe following M lines contains two integers describing the corresponding arc ofthe graph. Graph may contain loops and parallel arcs.

Output

On the first line of the output file print W --- theminimal sum Bob must have to remove all arcs from the graph. On the second lineprint K --- the number of moves Bob needs to do it. After that print K linesthat describe Bob's moves. Each line must first contain the number of thevertex and then '+' or '-' character, separated by one space. Character '+'means that Bob removes all arcs incoming into the specified vertex and '-' thatBob removes all arcs outgoing from the specified vertex.

Sample Input

3 6

1 2 3

4 2 1

1 2

1 1

3 2

1 2

3 1

2 3

Sample Output

5

3

1 +

2 -

2 +

题目分析:网络流裸题。我们拆点后把s向i的入点连一条流量为w-[i]的边,i,j有边就让i的入点和j的出点之间连INF,出点和t之间连w+[i]的边。

学了mhy12345学长用指针写池子以及这句“if(maxf) level[node]=-1;”(如果你已经把一个点的流量掏空了之后就不用走它了),以及当前弧优化(你把一个点的son掏空了之后就直接从它的下一个son开始访问),写出来的Dinic果然快。

CODE:

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
using namespace std;

const int maxn=1100;
const int maxm=50100;
const int oo=1000000001;

struct Edge
{
	int obj,flow;
	Edge *Next,*rev;
} e[(maxm+maxn)<<1];
Edge *head[maxn<<1];
Edge *nhead[maxn<<1];
int cur=-1;

int In[maxn];
int Out[maxn];

int level[maxn<<1];
int vis[maxn<<1];

int que[maxn<<1];
int he,ta;

int temp1[maxn];
int temp2[maxn];

int n,m;
int s,t;

void Add(int x,int y,int z)
{
	cur++;
	e[cur].obj=y;
	e[cur].flow=z;
	e[cur].Next=head[x];
	e[cur].rev=&e[cur+1];
	head[x]=e+cur;
	cur++;
	e[cur].obj=x;
	e[cur].flow=0;
	e[cur].Next=head[y];
	e[cur].rev=&e[cur-1];
	head[y]=e+cur;
}

bool Bfs()
{
	memset(level,-1,sizeof(level));
	memset(vis,false,sizeof(vis));
	for (int i=s; i<=t; i++) nhead[i]=head[i];
	
	he=0,ta=1;
	que[1]=s;
	
	level[s]=1;
	vis[s]=true;
	
	while (he<ta)
	{
		int node=que[ ++he ];
		Edge *p=head[node];
		while (p)
		{
			int son=p->obj;
			if ( !vis[son] && p->flow )
			{
				que[ ++ta ]=son;
				level[son]=level[node]+1;
				vis[son]=true;
			}
			p=p->Next;
		}
	}
	
	//for (int i=1; i<=ta; i++) printf("%d ",que[i]);
	//printf("\n");
	//printf("%d\n",vis[t]);
	return vis[t];
}

int Dfs(int node,int maxf)
{
	int nowf=0,nextf;
	if ( node==t || !maxf ) return maxf;
	Edge *p=nhead[node];
	while (p)
	{
		if ( p->flow && level[node]+1==level[ p->obj ] )
		{
			nextf=Dfs(p->obj, min(maxf,p->flow) );
			p->flow-=nextf;
			p->rev->flow+=nextf;
			nowf+=nextf;
			maxf-=nextf;
			if (maxf) nhead[node]=p;
		}
		p=p->Next;
	}
	if (maxf) level[node]=-1;
	return nowf;
}

int Dinic()
{
	int max_flow=0;
	while ( Bfs() )
	{
		max_flow+=Dfs(s,oo);
		//printf("do\n");
	}
	return max_flow;
}

int main()
{
	freopen("A.in","r",stdin);
	freopen("A.out","w",stdout);
	
	scanf("%d%d",&n,&m);
	for (int i=1; i<=n; i++) scanf("%d",&In[i]);
	for (int i=1; i<=n; i++) scanf("%d",&Out[i]);
	
	s=0,t=(n<<1)+1;
	for (int i=s; i<=t; i++) head[i]=NULL;
	for (int i=1; i<=n; i++) Add(s,i,Out[i]);
	for (int i=n+1; i<t; i++) Add(i,t,In[i-n]);
	
	for (int i=1; i<=m; i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		Add(x,n+y,oo);
	}
	
	int ans=Dinic();
	printf("%d\n",ans);
	
	int ans1=0;
	for (int i=1; i<=n; i++) if (!vis[i]) temp1[ ++ans1 ]=i;
	int ans2=0;
	for (int i=n+1; i<t; i++) if (vis[i]) temp2[ ++ans2 ]=i-n;
	
	printf("%d\n",ans1+ans2);
	for (int i=1; i<=ans1; i++) printf("%d -\n",temp1[i]);
	for (int i=1; i<=ans2; i++) printf("%d +\n",temp2[i]);
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值