POJ2125 Destroying The Graph

一.原题链接:http://poj.org/problem?id=2125

二.题目大意:给一个带点权的有向图,(点权:分为进度的权和出度的权)。然后每次可以移去图中的一个点,移去点的同时,可以选择移去进入点的所有边或者由点出发的所有边,但是有相应的花费,比如说点权的进度的权是5,移去所有进入该点的边,花费是5。求花费最少移去所有边。

三.思路:题目要求要移去所有的边,求最小点权。我们可以把原图拆成一个二分图(对应出度和入度),转换为网络流来求。

建图如下:

1.把原来每个点拆为2个点,分别为二分图的2边,如果原图中2点有连线,则二分图2边连线,容量为无穷大。

2.建立一个超级源点和左边每个点相连,容量为其出度的权大小。

3.建立一个超级汇点和右边每个点相连,容量为其入度的权大小。

跑一遍网络最大流,得到的就是最小割。

为什么最小割就是正确的答案呢,我们已经让中间的边为INF,无法被割到,因此割到的只能是左边或者右边的边,对应的就是选择去掉入度或者去掉出度,而且割的定义保证源点到汇点不联通,这样就等于去掉了所有的边。这么说吧,在左边去掉一条边,等于在中间去掉所有由这点出发的边,在右边去掉一条边,等于在中间去掉所有进去这一点的边。比如说对于下图,去掉s->1等于去掉中间的1->1,1->2。去掉1->t,相当于去掉1->1,2->1。

POJ2125 Destroying The Graph_第1张图片

     

图:构图方法


接下来就是输出最小割了,从s点开始,深度优先搜索,标记搜得到的点。由于被割的只有左边或者右边的边,

所以如果左边的点没有被访问过,说明割边在左边(比如说左边的1没有被访问过,则s->1是割边,也就是输出1 -。)

如果右边有被访问过,说明s能到达,那么肯定不能到达t,而它到t之间只剩下一条边,于是此边是割边。

四.代码:

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <cstdlib>

using namespace std;

const int INF = 0x3f3f3f3f,
          MAX_N = 300;

class Dinic
{
public:
    struct Edge
    {
        int v, w, next;
    };

    int cnt, head[MAX_N], dist[MAX_N], s, t;
    Edge edges[MAX_N*MAX_N];

    void init(int is, int it)
    {
        cnt = 0;
        s = is, t = it;
        memset(head, -1, sizeof(head));
    }

    void addEdge(int u, int v, int weight)
    {
        edges[cnt] = (Edge){v, weight, head[u]};
        head[u] = cnt++;
        edges[cnt] = (Edge){u, 0, head[v]};
        head[v] = cnt++;
    }

    bool BFS()
    {
        int i, cur;
        queue <int> que;
        que.push(s);
        memset(dist, -1, sizeof(dist));
        dist[s] = 0;
        while(!que.empty()){
            cur = que.front();
            que.pop();
            for(i = head[cur]; i != -1; i = edges[i].next)
                if(-1 == dist[edges[i].v] && edges[i].w){
                    dist[edges[i].v] = dist[cur] + 1;
                    que.push(edges[i].v);
                }
        }

        return dist[t] != -1;
    }

    int DFS(int start, int curFlow)
    {
        if(start == t)
            return curFlow;
        int i, minFlow = 0, v, temp;
        for(i = head[start]; i != -1; i = edges[i].next){
            v = edges[i].v;
            if(dist[start] == dist[v] - 1 && edges[i].w > 0){
                temp = DFS(v, min(edges[i].w, curFlow));
                edges[i].w -= temp;
                edges[i^1].w += temp;
                curFlow -= temp;
                minFlow += temp;
                if(0 == curFlow)
                    break;
            }
        }
        if(0 == minFlow)
            dist[start] = -2;
        return minFlow;
    }

    int maxFlow()
    {
        int res = 0;
        while(BFS()){
            res += DFS(s, INF);
        }
        return res;
    }
}G;

int nodeNum, edgeNum,
    inWeight[MAX_N], outWeight[MAX_N];
bool mp[MAX_N][MAX_N], visited[MAX_N];
vector <int> ans;

void read()
{
    int i, j, u, v;
    scanf("%d%d", &nodeNum, &edgeNum);

    for(i = 1; i <= nodeNum; i++)
        scanf("%d", &inWeight[i]);

    for(i = 1; i <= nodeNum; i++)
        scanf("%d", &outWeight[i]);

    memset(mp, 0, sizeof(mp));
    for(i = 1; i <= edgeNum; i++){
        scanf("%d%d", &u, &v);
        mp[u][v] = true;
    }
}

void buildG()
{
    int s = 2*nodeNum + 1,
        t = 2*nodeNum + 2,
        i, j;

    G.init(s, t);
    for(i = 1; i <= nodeNum; i++)
        G.addEdge(s, i, outWeight[i]);
    for(i = 1; i <= nodeNum; i++)
        G.addEdge(i+nodeNum, t, inWeight[i]);
    for(i = 1; i <= nodeNum; i++)
        for(j = 1; j <= nodeNum; j++)
            if(mp[i][j])
                G.addEdge(i, j+nodeNum, INF);
}

void DFS(int u)
{
    visited[u] = true;
    int i, v;
    for(i = G.head[u]; i != -1; i = G.edges[i].next){
        v = G.edges[i].v;
        if(G.edges[i].w > 0 && !visited[v])
            DFS(v);
    }
}

void setAns()
{
    ans.clear();
    int i;
    for(i = 1; i <= nodeNum; i++){
        if(!visited[i])
            ans.push_back(i);
        if(visited[i+nodeNum])
            ans.push_back(i+nodeNum);
    }
}

int main()
{
    //freopen("in.txt", "r", stdin);

    int i;
    read();
    buildG();
    printf("%d\n", G.maxFlow());
    memset(visited, 0, sizeof(visited));
    DFS(2*nodeNum+1);

    setAns();
    printf("%d\n", ans.size());
    for(i = 0; i < ans.size(); i++)
        if(ans[i] <= nodeNum)
            printf("%d -\n", ans[i]);
        else{
            printf("%d +\n", (ans[i] - nodeNum));
        }

}



你可能感兴趣的:(POJ2125 Destroying The Graph)