码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-06-18 09:51:29      阅读:121      评论:0      收藏:0      [点我收藏+]

标签:

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;
}

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

标签:

原文地址:http://blog.csdn.net/morestep/article/details/46538175

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!