poj 2125

题意就是 有一个图, 两种操作,一种是删除某点的所有出边,一种是删除某点的所有入边,各个点的不同操作分别有一个花费,现在我们想把这个图的边都删除掉,需要的最小花费是多少

那么本题的话,我们看到是要删除所有的边,但只需要在两个端点中的一端进行删除即可,这就可以联想到了最小点权覆盖了。

一般对有向图而言,我们经常进行的就是拆点,将每个点拆成两个点,一个点是代表边从这出来,一个代表边从这进去。就分别对应了两种操作了。

然后按照最小点权覆盖模型进行建图,求最大流。

残余网络中从超级源开始深搜所有可达点。

{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 }
原文地址:https://www.cnblogs.com/Missa/p/3027348.html