题意就是 有一个图, 两种操作,一种是删除某点的所有出边,一种是删除某点的所有入边,各个点的不同操作分别有一个花费,现在我们想把这个图的边都删除掉,需要的最小花费是多少
那么本题的话,我们看到是要删除所有的边,但只需要在两个端点中的一端进行删除即可,这就可以联想到了最小点权覆盖了。
一般对有向图而言,我们经常进行的就是拆点,将每个点拆成两个点,一个点是代表边从这出来,一个代表边从这进去。就分别对应了两种操作了。
然后按照最小点权覆盖模型进行建图,求最大流。
残余网络中从超级源开始深搜所有可达点。
{A}中不可达的点就是应该执行1操作的点。 残余网络中,左侧不可达的点表示被操作1的流选中了
{B}中可达的点就是应该执行2操作的点。 右侧可达的点表示从左侧开始无论如何也没有被流选中,只能留给操作2。
1 // File Name: 3308.cpp 2 // Author: Missa 3 // Created Time: 2013/4/17 星期三 11:24:48 4 5 #include<iostream> 6 #include<cstdio> 7 #include<cstring> 8 #include<algorithm> 9 #include<cmath> 10 #include<queue> 11 #include<stack> 12 #include<string> 13 #include<vector> 14 #include<cstdlib> 15 #include<map> 16 #include<set> 17 using namespace std; 18 #define CL(x,v) memset(x,v,sizeof(x)); 19 #define R(i,st,en) for(int i=st;i<en;++i) 20 #define LL long long 21 22 const int inf = 0x3f3f3f3f; 23 const int maxn = 200+5; 24 const int maxm = 45000; 25 struct Edge 26 { 27 int v, next; 28 int c; 29 }p[maxm << 1]; 30 int head[maxn], e; 31 int d[maxn], cur[maxn]; 32 int n, m, st, en; 33 void init() 34 { 35 e = 0; 36 //n = en;//记住n赋值为点的个数 37 memset(head, -1, sizeof(head)); 38 } 39 void addEdge(int u, int v, int c) 40 { 41 p[e].v = v; p[e].c = c; 42 p[e].next = head[u]; head[u] = e++; 43 swap(u,v); 44 p[e].v = v; p[e].c = 0; 45 p[e].next = head[u]; head[u] = e++; 46 } 47 int bfs(int st, int en) 48 { 49 queue <int > q; 50 memset(d, 0, sizeof(d)); 51 d[st] = 1; 52 q.push(st); 53 while (!q.empty()) 54 { 55 int u = q.front();q.pop(); 56 for (int i = head[u]; i != -1; i = p[i].next) 57 { 58 if (p[i].c > 0 && !d[p[i].v]) 59 { 60 d[p[i].v] = d[u] + 1; 61 q.push(p[i].v); 62 } 63 } 64 } 65 //for (int i = 0; i <= n; i ++) 66 // cout << d[i] << endl; 67 return d[en]; 68 } 69 int dfs(int u, int a) 70 { 71 if (u == en || a == 0) return a; 72 int f, flow = 0; 73 for (int& i = cur[u]; i != -1; i = p[i].next) 74 { 75 if (d[u] + 1 == d[p[i].v] && (f = dfs(p[i].v, min(a, p[i].c))) > 0) 76 { 77 p[i].c -= f; 78 p[i^1].c += f; 79 flow += f; 80 a -= f; 81 if (a == 0) break; 82 } 83 } 84 return flow; 85 } 86 int dinic(int st, int en) 87 { 88 int ret = 0, tmp; 89 while (bfs(st, en)) 90 { 91 for (int i = 0; i <= n; ++i) 92 cur[i] = head[i]; 93 ret += dfs(st, inf); 94 // cout << ret << endl; 95 } 96 return ret; 97 } 98 bool ok[maxn]; 99 void dfs(int u) 100 { 101 ok[u] = 1; 102 for (int i = head[u]; i != -1; i = p[i].next) 103 { 104 int v = p[i].v; 105 if (ok[v] == 0 && p[i].c) 106 dfs(v); 107 } 108 } 109 int main() 110 { 111 int c; 112 while (~scanf("%d%d",&n, &m)) 113 { 114 init(); 115 int tt = n; 116 st = 0, en = (n << 1) + 1; 117 for (int i = 1; i <= n; ++i) 118 { 119 scanf("%d", &c); 120 addEdge(i + n, en,c); 121 } 122 for (int i = 1; i <= n; ++i) 123 { 124 scanf("%d", &c); 125 addEdge(st, i, c); 126 } 127 for (int i = 1; i <= m; ++i) 128 { 129 int u,v; 130 scanf("%d%d", &u,&v); 131 addEdge(u, v + n, inf); 132 } 133 n = en; 134 int ans = dinic(st, en); 135 printf("%d\n",ans); 136 memset(ok, 0, sizeof(ok)); 137 dfs(st); 138 int res = 0; 139 for (int i = 1; i <= tt; ++i) 140 { 141 if (!ok[i]) 142 res ++; 143 if (ok[i + tt]) 144 res ++; 145 } 146 printf("%d\n",res); 147 for (int i = 1; i <= tt; ++i) 148 { 149 if (!ok[i]) 150 printf("%d -\n",i); 151 if (ok[i + tt]) 152 printf("%d +\n",i); 153 } 154 } 155 return 0; 156 }