51Nod 1757(二分&网络流)

二分答案,用网络流去判断,这个时间是否可行。m遍dfs求出每个非洞口节点到每个洞口的距离。设置一个虚拟源点和汇点,建图时把在x时间内可以到达洞口的点与洞口连一条容量为1 的边。把每个洞口分成x个点,连向汇点,容量为1.把每个非洞口节点与源点连一条边,容量为1。每个洞口的第i个节点向第i+1个节点连一条无穷大的边,然后就只要判断汇点的流量是否为n-m就行啦。

    #include<map>  
    #include<set>  
    #include<cmath>  
    #include<queue>  
    #include<bitset>  
    #include<math.h>  
    #include<vector>  
    #include<string>  
    #include<stdio.h>  
    #include<cstring>  
    #include<iostream>  
    #include<algorithm>  

    using namespace std;  
    const int N=2010;  
    const int mod=100000000;  
    const int MOD1=1000000007;  
    const int MOD2=1000000009;  
    const double EPS=0.00000001;  
    typedef long long ll;  
    const ll MOD=1000000007;  
    const int INF=1000000010;  
    const ll MAX=1ll<<55;  
    const double pi=acos(-1.0);  
    typedef double db;  
    typedef unsigned long long ull;  
    int n,m,q[N],d[50],dis[50][N];  
    int tot,u[100*N],v[500*N],pre[500*N],cap[500*N],flow[500*N];  
    void add(int a,int b) {  
        v[tot]=b;pre[tot]=u[a];u[a]=tot++;  
        v[tot]=a;pre[tot]=u[b];u[b]=tot++;  
    }  
    void dfs(int a,int b,int fa) {  
        dis[a][b]=dis[a][fa]+1;  
        for (int i=u[b];i!=-1;i=pre[i])  
        if (v[i]==fa) continue ;  
        else dfs(a,v[i],b);  
    }  
    void add_edge(int a,int b,int c,int f) {  
        v[tot]=b;cap[tot]=c;flow[tot]=f;pre[tot]=u[a];u[a]=tot++;  
        v[tot]=a;cap[tot]=0;flow[tot]=0;pre[tot]=u[b];u[b]=tot++;  
    }  
    bool bo[100*N];  
    int f[100*N],di[100*N],head[100*N];  
    bool BFS(int a,int b) {  
        int i,l=1,r=1;  
        memset(bo,0,sizeof(bo));  
        f[1]=a;bo[a]=1;di[a]=0;  
        for (;l<=r;l++)  
            for (i=u[f[l]];i!=-1;i=pre[i])  
            if (!bo[v[i]]&&cap[i]>flow[i]) bo[v[i]]=1,f[++r]=v[i],di[v[i]]=di[f[l]]+1;  
        return bo[b];  
    }  
    int DFS(int a,int b,int en) {  
        if (a==en||b==0) return b;  
        int ret=0,f;  
        for (int& i=u[a];i!=-1;i=pre[i])  
        if (di[v[i]]==di[a]+1&&(f=DFS(v[i],min(b,cap[i]-flow[i]),en)>0)) {  
            flow[i]+=f;flow[i^1]-=f;  
            b-=f;ret+=f;if (!b) break ;  
        }  
        return ret;  
    }  
    int judge(int a) {  
        int i,j,S=0,T=n+a*m+1,sum=0;  
        tot=0;memset(u,-1,sizeof(u));  
        for (i=1;i<=n;i++) if (!q[i]) add_edge(S,i,1,0);  
        for (i=1;i<=m;i++) {  
            for (j=1;j<=a;j++) add_edge(n+(i-1)*a+j,T,1,0);  
            for (j=1;j<a;j++) add_edge(n+(i-1)*a+j,n+(i-1)*a+j+1,INF,0);  
        }  
        for (i=1;i<=n;i++)  
        if (!q[i]) {  
            for (j=1;j<=m;j++)  
            if (dis[j][i]<=a) add_edge(i,n+(j-1)*a+dis[j][i],1,0);  
        }  
        for (i=0;i<=T;i++) head[i]=u[i];  
        while (BFS(S,T)) {  
            sum+=DFS(S,INF,T);  
            for (i=0;i<=T;i++) u[i]=head[i];  
        }  
        return sum==n-m;  
    }  
    int main()  
    {  
        int a,b,i,l,r,mid;  
        scanf("%d%d", &n, &m);  
        tot=0;memset(u,-1,sizeof(u));  
        for (i=1;i<n;i++) scanf("%d%d", &a, &b),add(a,b);  
        for (i=1;i<=m;i++) scanf("%d", &d[i]),q[d[i]]=1;  
        for (i=1;i<=m;i++) dis[i][0]=-1,dfs(i,d[i],0);  
        l=-1;r=n+1;mid=(l+r)>>1;  
        while (l+1<r)  
        if (judge(mid)) r=mid,mid=(l+r)>>1;  
        else l=mid,mid=(l+r)>>1;  
        printf("%d\n", r);  
        return 0;  
    }  


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值