POJ 2125 Destroying The Graph (最小点权覆盖集)

基本概念:

点覆盖集:(vertex covering set,VCS)是无向图的一个点集,使得该图中所有边都至少有一个端点在该集合内。形象地说是若干个点“覆盖”住了与它们邻接的边,这些边恰好组成了原边集。

最小点权覆盖集:(minimum weight vertex covering set,MinWVCS)是在带点权无向图G中,点权之和最小的点覆盖集。

题意:对一个有n个点,m条边的有向图,有两种操作:

A(u)操作:删除点u的所有出边,即∀(u, v)∈E,操作花费代价w+(u);

B(u)操作:删除点u的所有入边,即∀(v, u)∈E,操作花费代价w-(u);  求(1 )删除原图所有边所需的最小话费 (2 )输出方案,如1 - , 2 +。。。

对于第一问,用最小割最大流解决。建图:增加源点s和汇点t ,,根据题意构造二分图,X和Y点集分别代表A(u)和 B(u)。从源点s向所有X集合点增加弧(s, u), 容量为w+(u);然后从左右Y集合中点出发向汇点t,增加弧(u, t),容量为w-(u); 若原图存在一条有向边(u, v), 则增加弧(u, v),容量为INF。答案便是s到t的最大流。

第二问:求完最大流后,对残量网络进行dfs,沿着所有未满流的弧走。对于所有(s, u),如果u被访问了,则未在u节点进行A操作。由于对于一条边必然有一个端点进行了操作,所以对于所有(u, t),如果u节点被访问了,则必有操作B(u)。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;

const int maxn =  300;
const int INF = 1e9;
//Dinic模板
struct Edge
{
    int from, to, cap, flow;
};

int n, m, u, v, k, s, t;
vector<int> G[maxn];
vector<Edge> edges;
bool vis[maxn];
int d[maxn], cur[maxn];

inline void init()
{
    for(int i=0; i<=t; i++) G[i].clear();
    edges.clear();
}

void add(int from, int to, int cap)
{
    edges.push_back((Edge){from, to, cap, 0});
    edges.push_back((Edge){to, from, 0, 0});
    k = edges.size();
    G[from].push_back(k-2);
    G[to].push_back(k-1);
}

bool bfs()
{
    memset(vis, 0, sizeof(vis));
    queue<int> Q; Q.push(s);
    vis[s] = 1; d[s] = 0;
    while(!Q.empty())
    {
        int x = Q.front(); Q.pop();
        for(int i=0; i<G[x].size(); i++)
        {
            Edge& e = edges[G[x][i]];
            if(!vis[e.to] && e.cap > e.flow)
            {
                vis[e.to] = 1;
                d[e.to] = d[x] +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 max_flow()
{
    int flow = 0;
    while(bfs())
    {
        memset(cur, 0, sizeof(cur));
        flow += dfs(s, INF);
    }
    return flow;
}
//Dinic模板

void dfs1(int u) //对残量网络进行dfs
{
    vis[u] = 1;
    for(int i=0; i<G[u].size(); i++)
    {
        Edge v = edges[G[u][i]];
        if(v.flow < v.cap &&!vis[v.to])//沿着未满流的弧走
            dfs1(v.to);
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    //构图
    s = 0;  t = 2 * n + 1;
    init();
    int val;
    for(int i=1; i<=n; i++)
    {
        scanf("%d", &val);
        add(i + n, t, val);
    }
    for(int i=1; i<=n; i++)
    {
        scanf("%d", &val);
        add(s, i, val);
    }
    while(m--)
    {
        scanf("%d%d", &u, &v);
        add(u, v + n, INF);
    }
    printf("%d\n", max_flow());//输出第一问

    memset(vis, 0, sizeof(vis));
    dfs1(s);

    int ans_cnt = 0;
    for(int i=1; i<=n; i++)
    {
        if(!vis[i])  ans_cnt++;
        if(vis[i + n]) ans_cnt++;
    }
    printf("%d\n", ans_cnt); //输出第二问
    for(int i=1; i<=n; i++)
    {
        if(!vis[i])  printf("%d -\n", i);
        if(vis[i+n])   printf("%d +\n", i);
    }
    return 0;
}


你可能感兴趣的:(poj,网络流,最小点权覆盖集)