【网络流】【最小点权覆盖】【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个点所有的入边他要给Alice付Wi+元,如果他删除了所有的出边就需要给Alice付Wi元。

找到Bob删除图中所有边需要的最小花费。

【输入格式】

输入数据描述了Alice画下的图。

输入文件的第一行有两个数N,M(1<=N<=100,1<=M<=5000)。第二行有N个整数,描述了N个点的Wi+,同样的第三行是这N个点的Wi-。所有的费用都是正数并且不超过10^6。接下来的M行每行有两个数,代表有向图中相应的一条边。

【输出格式】

输出一行一个整数,即Bob的最小花费。

【样例输入】

3 6
1 2 3
4 2 1
1 2
1 1
3 2
1 2
3 1
2 3

【样例输出】

5

【提示】

样例的一个方案是:删除点1,2所有的入边,删除点2所有的出边。
输出格式和原题有所不同。原题要求输出方案。

【来源】

Northeastern Europe 2003,Northern Subregion (NEERC 2003)
POJ 2125 Destroying the Graph

题解:

通过题目可以发现,我们要求的就是在使用最小的点权的情况下选中所有边,每条边都可以被他的两个端点选中,且出入点权可能不同,于是就可以发现这是一个最小点权覆盖。

建边:

1>先建立虚拟源S和汇T,把每个点拆成两个,ia,ib。

2>从S向ia连一条流量为wi-的边,从ib向T连一条流量为wi+的边。

3>原图中的边从ua向vb连一条流量无穷大的边。

然后跑最大流即可。

Code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 110
#define M 5100
#define inf 0x3fffffff
using namespace std;
struct Edge{
    int v,next,cap;
}edge[10*M];
int n,m,num=-1,S,T,ans;
int w1[N],w2[N],head[2*N],pre[2*N],gap[2*N],dis[2*N],cur[2*N];
int in(){
    int x=0; char ch=getchar();
    while (ch<‘0‘ || ch>‘9‘) ch=getchar();
    while (ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x;
}
void add(int u,int v,int cap){
    edge[++num].v=v; edge[num].cap=cap;
    edge[num].next=head[u]; head[u]=num;
}
void build(){
    S=0,T=n<<1|1;
    for (int i=1; i<=n; i++)
        w1[i]=in(),add(i+n,T,w1[i]),add(T,i+n,0);
    for (int i=1; i<=n; i++)
        w2[i]=in(),add(S,i,w2[i]),add(i,S,0);
    for (int i=1; i<=m; i++){
        int u=in(),v=in();
        add(u,v+n,inf),add(v+n,u,0);
    }
}
void isap(){
    memset(dis,0,sizeof(dis));
    memset(gap,0,sizeof(gap));
    for (int i=0; i<=T; i++) cur[i]=head[i];
    int u=S,maxn=0,k=inf,v;
    gap[0]=T+1; pre[S]=S;
    while (dis[S]<=T){
        bool f=0;
        while (!f){
            f=1;
            for (int i=cur[u]; i!=-1; i=edge[i].next){
                v=edge[i].v;
                if (edge[i].cap>0 && dis[u]==dis[v]+1){
                    k=min(k,edge[i].cap);
                    pre[v]=u; cur[u]=i; u=v;
                    if (u==T){
                        for (u=pre[u]; v!=S; v=u,u=pre[u]){
                            edge[cur[u]].cap-=k;
                            edge[cur[u]^1].cap+=k;
                        }
                        maxn+=k; k=inf;
                    }
                    f=0; break;
                }
            }
        }
        int minn=T+1;
        for (int i=head[u]; i!=-1; i=edge[i].next){
            v=edge[i].v;
            if (edge[i].cap>0 && dis[v]<minn)
                cur[u]=i,minn=dis[v];
        }
        gap[dis[u]]--;
        if (!gap[dis[u]]) break;
        dis[u]=minn+1; gap[dis[u]]++; u=pre[u];
    }
    ans=maxn;
}
int main(){
    memset(head,-1,sizeof(head));
    n=in(); m=in();
    build(); isap();
    printf("%d\n",ans);
    return 0;
}
时间: 2024-12-16 23:03:13

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

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 B

POJ2125 Destroying The Graph 最小点权覆盖

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

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

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

hdu 1565&amp;hdu 1569(网络流--最小点权值覆盖)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7717    Accepted Submission(s): 2911 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数

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: 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

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

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

poj 3308 Paratroopers 最小割 最小点权覆盖

题目链接:http://poj.org/problem?id=3308 题意: 有一个M*N的图,上面的一些点上有伞兵. 可以设置一些枪在每行或者每列上,通过射击,这行或这列的伞兵就会被消灭.每个枪的设置有一个花费,如果设置多个枪,那么花费是设置每个枪的乘积. 问消灭所有伞兵最少的花费是多少. 思路: 每个点的伞兵至少要用那一列或者那一行设置的枪去消灭,那么就可以应用点覆盖的模型.把伞兵看成是一条边,这条边至少要用一个点来覆盖. 而题目中最终花费是所有花费的乘积,那么可以用对数log(x)+lo

poj3308 Paratroopers --- 最小点权覆盖-&amp;gt;最小割

题目是一个非常明显的二分图带权匹配模型, 加入源点到nx建边,ny到汇点建边,(nx.ny)=inf建边.求最小割既得最小点权覆盖. 在本题中因为求的是乘积,所以先所有取log转换为加法,最后再乘方回来. #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #in