标签:
| Time Limit: 2000MS | Memory Limit: 65536K | |||
| Total Submissions: 7570 | Accepted: 2423 | Special Judge | ||
Description
Input
Output
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 +
题意:给出N个点,N条边。有两种操作。一种是选择某个点把这个点的入边全部删除。另一种是给出选择某个点把这个点的出边全部删除。
给出选择每个点的两种操作所需要的花费。求删除所有边所需要的最小花费。
思路:设删除入边为操作a,删除出边为操作b。对于每条边(u,v)来讲,必须至少选择a(v)或者b(u)来进行操作,才能删除这条边。
这就符合点覆盖集的模型。
对于每个点,可以拆分成两个点,一种对应于操作a(N+1,2*N),另一种对应于操作b(1,N)。
所以增加源点s(0)和汇点t(2*N+1)。对于对应于删除出边的操作b。从s到每个点连一条边,容量为对应花费。
对于删除入边的操作a,每个点到t连一条边 ,容量为对应花费。
然后图中给出点边(i, j),连接点(i,j+N),容量为inf.
然后求最小割,就是最小花费。
对于求割边。在最后一次bfs操作中已经标记了点s能够到达的点.
所以对于(1~N)的点。如果点s不能到达这个点,那么对应点边就是割边。这个点就是删除出边操作。
对于(N+1~2*N)的点。如果点s能够到达这个点,那么对应点就是割边。这个点就是删除入边操作。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
using namespace std;
int N, M;
#define maxn 110
const int inf = 0x3f3f3f3f;
struct Edge
{
int from, to, cap, flow;
Edge(int f, int t, int c, int fl)
{
from = f; to = t; cap = c; flow = fl;
}
};
vector <Edge> edges;
vector <int> G[maxn*2];
int vis[maxn*2], d[maxn*2], cur[maxn*2];
int n, m, s, t;
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool bfs()
{
memset(vis, 0, sizeof(vis));
vis[s] = 1;
d[s] = 0;
queue <int> q;
q.push(s);
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = 0; i < G[u].size(); i++)
{
Edge &e = edges[G[u][i]];
if(!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[u]+1;
q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int x, int a)
{
if(x == t || a == 0) return a;
int flow = 0, f;
for(int &i = cur[x]; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0)
{
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if(a == 0) break;
}
}
return flow;
}
int Maxflow()
{
int flow = 0;
while(bfs())
{
memset(cur, 0, sizeof(cur));
flow += dfs(s, inf);
}
return flow;
}
int win[maxn], wout[maxn];
int main()
{
while(~scanf("%d%d", &N, &M))
{
edges.clear();
for(int i = 0; i < maxn*2; i++) G[i].clear();
for(int i = 1; i <= N; i++) scanf("%d", &win[i]);
for(int i = 1; i <= N; i++) scanf("%d", &wout[i]);
s = 0; t = 2*N+1; n = N;
for(int i = 1; i <= N; i++)
{
AddEdge(s, i, wout[i]);
AddEdge(i+N, t, win[i]);
}
for(int i = 1; i <= M; i++)
{
int a, b;
scanf("%d%d", &a, &b);
AddEdge(a, b+N, inf);
}
int ans = Maxflow();
printf("%d\n", ans);
int cnt = 0;
for(int i = 1; i <= 2*N; i++)
{
if(vis[i] && i > N) cnt++;
if(!vis[i] && i <= N) cnt++;
}
printf("%d\n", cnt);
for(int i = 1; i <= 2*N; i++)
{
if(vis[i] && i > N) printf("%d +\n", i-N);
if(!vis[i] && i <= N) printf("%d -\n", i);
}
}
return 0;
}
poj 2125 Destroying The Graph 最小点权覆盖集+拆点+求割边
标签:
原文地址:http://www.cnblogs.com/titicia/p/4695479.html