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 }

 

你可能感兴趣的:(poj)