bzoj1585 [Usaco2009 Mar]Earthquake Damage 2 地震伤害 最小割

Description


Farmer John的农场里有P个牧场,有C条无向道路连接着他们,第i条道路连接着两个牧场Ai和Bi,注意可能有很多条道路连接着相同的Ai和Bi,并且Ai有可能和Bi相等。Farmer John在1号牧场里。由于地震,某些牧场被损坏,但由于信春哥,C条道路没有一条损坏。有N头奶牛,他们在不同的牧场里,于是N <= P。他们一一向Farmer John报告。第i头奶牛报告给Farmer John一个整数Report_i,代表第Report_i个牧场没有损毁,但不能够从第Report_i个牧场经过一些没有损坏的牧场到达1号牧场。现在Farmer John想知道,最少有多少损坏的牧场。

1 <= P <=3000
1 <= C <=20000

Solution


感觉越做越傻了
题意可以转化为最少去掉多少个点使得所有report和1不连通
对于非reprot点拆点连容量为1的边,所有report点向汇点连边,最小割就是答案
正确性可以考虑最小割的定义和建图方式

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))

const int INF=0x3f3f3f3f;
const int N=12005;
const int E=400005;

struct edge {int y,w,next;} e[E];

int dis[N],queue[N],vis[N];
int cur[N],ls[N],edCnt=1;

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void add_edge(int x,int y,int w) {
    e[++edCnt]=(edge) {y,w,ls[x]}; ls[x]=edCnt;
    e[++edCnt]=(edge) {x,0,ls[y]}; ls[y]=edCnt;
}

bool bfs(int st,int ed) {
    fill(dis,-1); dis[st]=1;
    int head=1,tail=0;
    queue[++tail]=st;
    while (head<=tail) {
        int now=queue[head++];
        for (int i=ls[now];i;i=e[i].next) {
            if (e[i].w>0&&dis[e[i].y]==-1) {
                dis[e[i].y]=dis[now]+1;
                queue[++tail]=e[i].y;
                if (e[i].y==ed) return true;
            }
        }
    }
    return false;
}

int find(int now,int ed,int mn) {
    if (now==ed||!mn) return mn;
    int ret=0;
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].w>0&&dis[now]+1==dis[e[i].y]) {
            int d=find(e[i].y,ed,std:: min(mn-ret,e[i].w));
            e[i].w-=d; e[i^1].w+=d; ret+=d;
            if (ret==mn) break;
        }
    }
    return ret;
}

int dinic(int st,int ed) {
    int ret=0;
    while (bfs(st,ed)) {
        ret+=find(st,ed,INF);
    }
    return ret;
}

int main(void) {
    int n=read(),m=read(),k=read(); vis[1]=1;
    rep(i,1,m) {
        int x=read(),y=read();
        add_edge(x+n,y,INF); add_edge(y+n,x,INF);
    }
    rep(i,1,k) vis[read()]=1;
    rep(i,1,n) if (!vis[i]) {
        add_edge(i,i+n,1);
    } else {
        add_edge(i,i+n,INF);
        if (i!=1) add_edge(i+n,n*2+1,INF);
    }
    printf("%d\n", dinic(1,n*2+1));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/80328237