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

来源:互联网 发布:xquartz mac教程 编辑:程序博客网 时间:2024/06/04 23:18

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 61 2 34 2 11 21 13 21 23 12 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 0x3fffffffusing 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;}
1 0
原创粉丝点击