Destroying The Graph

Description

Alice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that Bob tries to destroy it. In a move he may take any vertex of the graph and remove either all arcs incoming into this 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 outgoing arcs 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 input file contains N and M (1 <= N <= 100, 1 <= M <= 5000). The second line contains N integer numbers specifying Wi+. The third line defines Wi- in a similar way. All costs are positive and do not exceed 106 . Each of the following M lines contains two integers describing the corresponding arc of the graph. Graph may contain loops and parallel arcs.

Output

On the first line of the output file print W --- the minimal sum Bob must have to remove all arcs from the graph. On the second line print K --- the number of moves Bob needs to do it. After that print K lines that describe Bob's moves. Each line must first contain the number of the vertex and then '+' or '-' character, separated by one space. Character '+' means that Bob removes all arcs incoming into the specified vertex and '-' that Bob 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 +
题意:对每个点可以选择删除它的所有入边,也可以选择删除它所有出边,每个点的每种删除方法会消耗不同的钱。
问:用最少的钱删掉所有边并输出一个删除方案。
分析:对每个点有两种操作,一种是删除它所有入边,消费是x,另一种是删除它所有出边,消费是y。将每个点拆成两个点u1,u2。s到u1为删除点所有出边的花费,u2到t为删除点所有入边的花费。对图中的每条边(u,v),有u1到v2是正无穷。即一个二分图再加上源跟汇,最大流即为最小费用。
题目要求输出方案,对每个点,如果u1在割中,则u有一个删出边的操作,如果u2在割中,则u有一个删除入边的操作。
如何判断点在s临边的个还是t临边的割。在二分图里,从s能到达的最后一个点与t成一最小割,如果s是不能到达的点,则s与该点成一最小割。所以最小割不能简单的认为是流路中容量最小的边,因为会有容量最小且相等的。在二分图结构里,因为每个流路只有三条边,可能会出现s->u->v->t,而u->v是容量无穷的,所以不会成个最小割,如果s->u跟v->t容量一样小,则可认为最小割是任选一个。对于任意图,一个流路会出现多条边容量一样是最小的。这种情况下会有s->a->b->c->d->e->...->t。则第一个满流量的或者最后一个满流量的边是最小割。其实二分图的最小割也是满足这个说法。
代码:
#include <stdio.h>  
#include 
<string.h> 
#include 
<queue> 
#include 
<algorithm>
#include 
<iostream>
#define Min(a, b) (a) < (b) ? a : b  
#define Max(a, b) (a) > (b) ? a : b
using  namespace std;  
const  int MAXN = 2005;  
const  int MAXM = 700000;  
const  int INF = 1100000000;  
struct  Edge  
{  
    
int  st, ed;  
    
int  next;  
    
int  flow; 
    
int cap; 
}edge[MAXM]; 
int  head[MAXN], level[MAXN], que[MAXN], E;
void add(int u, int v, int w)  
{  
    edge[E].flow 
= 0;  
    edge[E].cap 
= w;
    edge[E].st 
= u;  
    edge[E].ed 
= v;  
    edge[E].next 
= head[u];  
    head[u] 
= E++;      
    edge[E].flow 
= 0
    edge[E].cap 
= 0
    edge[E].st 
= v;  
    edge[E].ed 
= u;  
    edge[E].next 
= head[v];  
    head[v] 
= E++;  
}
int dinic_bfs(int src, int dest, int ver)        
{        
    
int i, j;         
    
for (i = 0; i <= ver; i++)
    {    
        level[i] 
= -1;
    }
    
int rear = 1;        
    que[
0= src; level[src] = 0;        
    
for(i = 0; i < rear; i++
    {        
          
for(j = head[que[i]]; j != -1; j = edge[j].next)
         {        
            
if(level[edge[j].ed] == -1 && edge[j].cap > edge[j].flow)        
            {        
              level[edge[j].ed] 
= level[que[i]]+1;        
              que[rear
++= edge[j].ed;        
            }
         }
    }
    
return  level[dest] >= 0;        
}        
     
int dinic_dfs(int src, int dest, int ver)        
{        
    
int stk[MAXN], top = 0;        
    
int ret = 0, cur, ptr, pre[MAXN], minf, i;        
    
int del[MAXN];        
    
for (i = 0; i <= ver; i++
    {
        del[i] 
= 0;
    }
    stk[top
++= src;         
    pre[src] 
= src; 
    cur 
= src;        
    
while(top)        
    {        
        
while(cur != dest && top)        
        {        
            
for(i = head[cur]; i != -1; i = edge[i].next)        
            {        
                
if(level[edge[i].ed] == level[cur] + 1 && edge[i].cap > edge[i].flow  && !del[edge[i].ed])        
                {        
                    stk[top
++= edge[i].ed;      
                    cur 
= edge[i].ed;        
                    pre[edge[i].ed] 
= i;                       
                    
break;     
                }        
            }     
            
if(i == -1)       
            {        
                del[cur] 
= 1;        
                top
--;        
                
if(top) cur = stk[top-1];        
            }        
        }                
        
if(cur == dest)        
        {       
            minf 
= INF;        
            
while(cur != src)        
            {        
                cur 
= pre[cur];        
                
if(edge[cur].cap - edge[cur].flow < minf) minf = edge[cur].cap - edge[cur].flow;        
                cur 
= edge[cur].st;        
            }
            cur 
= dest;        
            
while(cur != src)        
            {        
                cur 
= pre[cur];        
                edge[cur].flow 
+= minf;        
                edge[cur
^1].flow -= minf;        
                
if(edge[cur].cap - edge[cur].flow == 0)
                {
                     ptr 
= edge[cur].st;
                }
                cur 
= edge[cur].st;        
            }        
            
while(top > 0&& stk[top-1!= ptr) top--;        
            
if(top)  cur = stk[top-1];        
            ret 
+= minf;      
        }        
    }        
    
return ret;        
}        
int Dinic(int src, int dest, int ver)        
{        
    
int  ret = 0, t;        
    
while(dinic_bfs(src, dest, ver))        
    {        
        t 
= dinic_dfs(src, dest, ver);        
        
if(t) ret += t;        
        
else  break;        
    }        
    
return ret;        
}
int visit[MAXN];
void dfs(int u)
{
    visit[u] 
= 1;
    
int i;
    
for (i = head[u]; i != -1; i = edge[i].next)
    {
        
if (!visit[edge[i].ed] && edge[i].cap > edge[i].flow)
        {
            visit[edge[i].ed] 
= 1;
            dfs(edge[i].ed);
        }
    }
}
int main()
{
    
int n, m, i, u, v, w;
    scanf(
"%d%d"&n, &m);
    
int s = 0, t = n + n + 1, ver = t + 1;
    E 
= 0;
    
for (i = 0; i <= ver; i++)
    {
        head[i] 
= -1;
    }
    
for (i = 1; i <= n; i++)
    {
        scanf(
"%d"&w);
        add(i 
+ n, t, w); 
    }
    
for (i = 1; i <= n; i++)
    {
        scanf(
"%d"&w);
        add(
0, i, w);
    }
    
while (m--)
    {
        scanf(
"%d%d"&u, &v);
        add(u, v 
+ n, INF);
    }
    
int ans = Dinic(s, t, ver);
    
for (i = 0; i <= ver; i++)
    {
        visit[i] 
= 0;
    }
    dfs(s);
    
int num = 0;
    
for (i = 1; i <= n; i++)
    {
        
if (visit[i + n]) num++;
        
if (!visit[i]) num++;
    }
    printf(
"%d\n%d\n", ans, num);
    
for (i = 1; i <= n; i++)
    {
        
if (visit[i + n])
        {
            printf(
"%d +\n", i);
        }
        
if (!visit[i])
        {
            printf(
"%d -\n", i); 
        }
    }
    
return 0;
}
/*
3 2
2 1 1
3 1 3
2 1
3 1


3 2
3 1 1
3 1 3
2 1
3 1


3 2
3 1 1
3 1 2
2 1
3 1

3 2
3 1 1
3 1 1
2 1
3 1

2 1
1 1
1 1
1 2

*/