POJ2125 Destroying The Graph (最小点权覆盖集)(网络流最小割)

Destroying The Graph

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 8158   Accepted: 2620   Special Judge

Description

Alice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that Bob tries to destroy it. In a move he may take any vertex of the graph and remove either all arcs incoming into this vertex, or all arcs outgoing from this vertex.
Alice assigns two costs to each vertex: Wi+ and Wi-. If Bob removes all arcs incoming into the i-th vertex he pays Wi+ dollars to Alice, and if he removes outgoing arcs he pays Wi- dollars.

Find out what minimal sum Bob needs to remove all arcs from the graph.

Input

Input
file describes the graph Alice has drawn. The first line of the input
file contains N and M (1 <= N <= 100, 1 <= M <= 5000). The
second line contains N integer numbers specifying Wi+. The third line defines Wi- in a similar way. All costs are positive and do not exceed 106
. Each of the following M lines contains two integers describing the
corresponding arc of the graph. Graph may contain loops and parallel
arcs.

Output

On
the first line of the output file print W --- the minimal sum Bob must
have to remove all arcs from the graph. On the second line print K ---
the number of moves Bob needs to do it. After that print K lines that
describe Bob‘s moves. Each line must first contain the number of the
vertex and then ‘+‘ or ‘-‘ character, separated by one space. Character
‘+‘ means that Bob removes all arcs incoming into the specified vertex
and ‘-‘ that Bob removes all arcs outgoing from the specified vertex.

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 +【分析】首先得拆点,一个点拆成in和out。很明显就是求最小点权覆盖集。最小点权覆盖集的求解可以借鉴二分图匹配的最大流解法。 再加上额外的源点S和汇点T后,将匹配以一条s-u-v-t形式的流路径串联起来。匹配的限制在顶点上,恰当的利用了流的容量限制。 而点覆盖集的限制在边上,最小割是最大流的对偶问题,对偶往往是将问题的性质从顶点转边,从边转顶点。可以尝试转最小割模型。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <queue>
#include <vector>
#define inf 0x7fffffff
#define met(a,b) memset(a,b,sizeof a)
typedef long long ll;
using namespace std;
const int N = 205;
const int M = 11005;
int read() {int x=0,f=1;char c=getchar();while(c<‘0‘||c>‘9‘) {if(c==‘-‘)f=-1;c=getchar();}while(c>=‘0‘&&c<=‘9‘) {x=x*10+c-‘0‘;c=getchar();}return x*f;}
int n,m,cnt;
int win[N],wout[N];
bool flag;
int toto=0;
struct Dinic {
    int s,t;
    struct Edge {
        int nxt,to,cap,flow;
    } edg[M];
    bool vv[N];
    bool vis[N];
    int d[N];
    int h[N];
    int cur[N];
    void init() {
        met(h,-1);
    }
    void AddEdge(int x,int y,int z) {
        edg[toto].to=y;
        edg[toto].nxt=h[x];
        edg[toto].cap=z;
        h[x]=toto++;
        edg[toto].to=x;
        edg[toto].nxt=h[y];
        h[y]=toto++;
    }
    bool BFS() {
        memset(vis,0,sizeof(vis));
        queue<int>q;
        q.push(s);
        d[s]=0;
        vis[s]=1;
        while (!q.empty()) {
            int x = q.front();
            q.pop();
            for (int i = h[x]; i!=-1; i=edg[i].nxt) {
                int v=edg[i].to;
                if (!vis[v] && edg[i].cap > edg[i].flow) {
                    vis[v]=1;
                    d[v] = d[x]+1;
                    q.push(v);
                    if(flag)vv[v]=true;
                }
            }
        }
        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!=-1; i=edg[i].nxt) {
            int v=edg[i].to;
            if (d[x]+1 == d[v] && (f=DFS(v,min(a,edg[i].cap-edg[i].flow)))>0) {
                edg[i].flow+=f;
                edg[i^1].flow-=f;
                flow+=f;
                a-=f;
                if (a==0)
                    break;
            }
        }
        return flow;
    }

    int Maxflow(int s,int t) {
        this->s=s;
        this->t=t;
        int flow = 0;
        while (BFS()) {
            for(int i=0; i<=t; i++)cur[i]=h[i];
            flow+=DFS(s,inf);
        }
        return flow;
    }

} dc;

int main() {
    while (~scanf("%d%d",&n,&m)) {
        dc.init();
        met(wout,0);
        met(win,0);
        flag=false;
        for(int i=1; i<=n; i++)win[i]=read();
        for(int i=1; i<=n; i++)wout[i]=read();
        while(m--) {
            int u=read();
            int v=read();
            dc.AddEdge(u,v+n,inf);
        }
        for(int i=1; i<=n; i++) {
            dc.AddEdge(0,i,wout[i]);
            dc.AddEdge(i+n,2*n+1,win[i]);
        }
        printf("%d\n",dc.Maxflow(0,2*n+1));
        int sum=0;
        flag=true;
        dc.BFS();
        for(int i=1; i<=n; i++) {
            if(!dc.vv[i])sum++;
            if(dc.vv[n+i])sum++;
        }
        printf("%d\n",sum);
        for(int i=1; i<=n; i++) {
            if(!dc.vv[i])printf("%d -\n",i);
            if(dc.vv[n+i])printf("%d +\n",i);
        }
    }
    return 0;
}

时间: 2024-11-03 05:25:48

POJ2125 Destroying The Graph (最小点权覆盖集)(网络流最小割)的相关文章

HDU 1569 - 方格取数(2) - [最大点权独立集与最小点权覆盖集]

嗯,这是关于最大点权独立集与最小点权覆盖集的姿势,很简单对吧,然后开始看题. HDU1569: Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多个测试实例,

HLG1407Leyni的游戏【最小点权覆盖集】

大意: 给你一个n行m列的矩阵 1 2 1 1 每次操作可使一整行或一整列的一个数减少1(如果是0则不变) 问最少多少次操作会使所有的数变为零 分析: 该题很像poj消灭外星人的那道题 思路也差不很多 将x轴当左集合,y轴当右集合,边权值为所在点的数字 那么一条边就代表了矩阵中的一个点 只要找出最小的权值去覆盖所有的边就能把所有的数字变为零 也就是传说中的最小点权覆盖集 最小点权覆盖集 = 最大权匹配 KM跑一遍就可以了 但是需要注意的是如果两边点的个数不相等 那么我们用虚拟点代替就可以了 代码

poj 2125 Destroying The Graph 最小点权覆盖集+拆点+求割边

Destroying The Graph Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7570   Accepted: 2423   Special Judge Description Alice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that B

【网络流专题4】 最小点权覆盖集

Ahead 11.1.2018 例题 poj 2125 题意为选取一些点使得覆盖所有的边 仍然是最小割与割点,对于每一条边的两个点,从源点向每个点连一条删除从这个点出发的所有边的权值 即W- ,同理对每一个点向汇点连W+ 中间部分为图的边关系. 然后最大流即可 针对方案需要进行一次深搜,对于与源点连接的点,如果不能被访问到,那么一定是割去的,对于与汇点相连的如果被访问到那么一定是割去的 代码 #include <iostream> #include <cstdlib> #inclu

POJ 2125 Destroying the Graph 二分图最小点权覆盖

Destroying The Graph Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8198   Accepted: 2635   Special Judge Description Alice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that B

POJ 2125 --Destroying The Graph【最小割解决 &quot;最小点权覆盖问题&quot; &amp;&amp; 输出解(割边集) &amp;&amp; 各种不懂】

Destroying The Graph Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7597   Accepted: 2434   Special Judge Description Alice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that B

POJ2125 Destroying The Graph 二分图 + 最小点权覆盖 + 最小割

思路来源:http://blog.csdn.net/lenleaves/article/details/7873441 求最小点权覆盖,同样求一个最小割,但是要求出割去了那些边, 只要用最终的剩余网络进行一次遍历就可以了,比较简单. 建图:同样是一个二分图,左边的点代表去掉出边, 右边的点代表去掉入边(小心别弄混),左边去掉出边的点与源点相连, 容量为wi- . 然后更据给出的弧进行连线,权值为INF 使用很好理解的EK算法:(360MS) //#pragma comment(linker, "

POJ2125 Destroying The Graph 最小点权覆盖

题目链接: poj2125 题意: 给出一张N个顶点M条边的有向图. 对于每个顶点x,有两种操作: 1,删除所有进入x的边,花费为a; 2.删除所有从x出去的边,花费为b. 问把图中所有边删除所需要的最小花费.并输出对应的操作. 解题思路: 由题目条件(删除入边,删除出边)首先想到应该是拆点. 这样题目的问题转化为最小点权覆盖问题.即用最少(花费)的顶点覆盖所有边 对于这个问题,我们可以用网络流中的最小割解决,方法如下: 源点连接拆后的出点,容量为b 汇点连接拆后的入点,容量为a 已有边容量为无

【网络流】【最小点权覆盖】【NEERC 2003】【POJ2125】【cogs 1575】有向图破坏

1575. [NEERC 2003][POJ2125]有向图破坏 ★★★ 输入文件:destroyingthegraph.in 输出文件:destroyingthegraph.out 简单对比 时间限制:1 s 内存限制:256 MB [题目描述] Alice和Bob正在玩如下的游戏.首先Alice画一个有N个顶点,M条边的有向图.然后Bob试着摧毁它.在一次操作中他可以找到图中的一个点,并且删除它所有的入边或所有的出边. Alice给每个点定义了两个值:Wi+和Wi-.如果Bob删除了第i个点