bzoj 1585: [Usaco2009 Mar]Earthquake Damage 2 地震伤害

1585: [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想知道,最少有多少损坏的牧场。

Input

第一行三个整数 P,C,N

第2..C+1行:每行两个整数Ai,Bi

第C+2..C+N+1行:第C+1+i行包含一个整数,Report_i

Output

一个整数,代表最少有多少损坏的牧场

Sample Input

5 5 2
1 2
2 3
3 5
2 4
4 5
4
5

Sample Output

1
【数据规模】
1 <= P <=3000
1 <= C <=20000

题解:

拆点,最小割。。。

由于1到不了给定的一些点,那么就是求图中的割,将给定的点向T连一条边权无穷大的边,保证割使1和这些点分离。。

题目中还说给定的点没有毁坏,以此将一个点x裂成x,x'

若是1或是给定的点,x->x'  ∞

反之x->x'  1

对于相邻的<x,y>

x'->y  ∞

y'->x  ∞

#include<stdio.h>
#include<iostream>
using namespace std;
const int N=6005;
const int M=100005;
int n,m,k,i,x,y,src,tar,ans,dis[N],gap[N],p[N];
int tot,head[N],Next[M],to[M],v[M];
void add(int x,int y,int z)
{
    to[tot]=y;
    v[tot]=z;
    Next[tot]=head[x];
    head[x]=tot++;
}
inline void read(int &v){
    char ch,fu=0;
    for(ch='*'; (ch<'0'||ch>'9')&&ch!='-'; ch=getchar());
    if(ch=='-') fu=1, ch=getchar();
    for(v=0; ch>='0'&&ch<='9'; ch=getchar()) v=v*10+ch-'0';
    if(fu) v=-v;
}
int isap(int x,int s)
{
    if(x==tar) return s;
    int flow=0,i,Min=n-1;
    for(i=head[x];i!=-1;i=Next[i])
    {
        int y=to[i];
        if(v[i]>0)
        {
            if(dis[x]==dis[y]+1)
            {
                int tmp=isap(y,min(s-flow,v[i]));
                flow+=tmp;
                v[i]-=tmp;
                v[i^1]+=tmp;
            }
            Min=min(Min,dis[y]);
        }
        if(flow==s) return flow;
        if(dis[src]==n) return flow;
    }
    if(flow==0)
    {
        gap[dis[x]]--;
        if(gap[dis[x]]==0) dis[src]=n;
        dis[x]=Min+1;
        gap[dis[x]]++;
    }
    return flow;
}
int main()
{
    read(n),read(m),read(k);
    for(i=1;i<=n*2+2;i++) head[i]=-1;
    src=n*2+1,tar=n*2+2;
    add(src,1,1e9);add(1,src,0);
    for(i=1;i<=m;i++)
    {
        read(x),read(y);
        add(x+n,y,1e9);add(y,x+n,0);
        add(y+n,x,1e9);add(x,y+n,0);
    }
    for(i=1;i<=k;i++)
    {
        read(x);
        add(x+n,tar,1e9);
        add(tar,x+n,0);
        p[x]=1;
    }
    for(i=1;i<=n;i++)
    {
        if(i==1||p[i])
        {
            add(i,i+n,1e9);
            add(n+i,i,0);
        } else
        {
            add(i,n+i,1);
            add(n+i,i,0);
        }
    }
    n=n*2+2;
    gap[0]=n;
    while(dis[src]<n)
        ans+=isap(src,1e9);
    cout<<ans;
    return 0;
}

  

转载于:https://www.cnblogs.com/lwq12138/p/5692919.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值