【BubbleCup X】D. Exploration plan

这个题首先一眼能看出二分答案……

毕竟连可爱的边界都给你了。

下面就是怎么check

首先预处理跑一遍floyed,预处理出最短路。

用网络流判断能否达到即可。

#include<bits/stdc++.h>
typedef long long ll;
const int N=2010;
const int M=1000005;
const int inf=1e9+7;
using namespace std;
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
namespace MaxFlow{
    
struct Edge{int u,v,next,f;}G[M];
int head[N],level[N],tot;
inline void init(){tot=1;memset(head,0,sizeof(head));}
inline void addedge(int u,int v,int f){
    G[++tot].u=u;G[tot].v=v;G[tot].f=f;G[tot].next=head[u];head[u]=tot;
    G[++tot].u=v;G[tot].v=u;G[tot].f=0;G[tot].next=head[v];head[v]=tot;
}
inline bool bfs(int s,int t){
    memset(level,0,sizeof(level));queue<int>q;
    q.push(s);level[s]=1;
    while(!q.empty()){
        int u=q.front();q.pop();
        if(u==t)return 1;
        for(int i=head[u];i;i=G[i].next){
            int v=G[i].v,f=G[i].f;
            if(f&&!level[v])level[v]=level[u]+1,q.push(v);
        }
    }
    return 0;
}
inline int dfs(int u,int maxf,int t){
    if(u==t)return maxf;int rat=0;
    for(int i=head[u];i;i=G[i].next){
        int v=G[i].v,f=G[i].f;
        if(f&&level[v]==level[u]+1){
            f=dfs(v,min(maxf-rat,f),t);
            rat+=f;G[i].f-=f;G[i^1].f+=f;
        }
    }
    if(!rat)level[u]=inf;
    return rat;
}
inline int dinic(int s,int t){
    int ans=0;
    while(bfs(s,t))ans+=dfs(s,inf,t);
    return ans;
}
    
}
int n,m,p,q,f[N],dis[1010][1010];
inline bool check(int x){
    MaxFlow::init();int s=0,t=n*2+1;
    for(int i=1;i<=n;i++)MaxFlow::addedge(s,i,f[i]);
    for(int i=1;i<=n;i++)MaxFlow::addedge(i+n,t,1);
    for(int i=1;i<=n;i++)if(f[i])for(int j=1;j<=n;j++)
    if(dis[i][j]<=x)MaxFlow::addedge(i,j+n,1);
    int ans=MaxFlow::dinic(s,t);
    return ans>=q;
}
int main(){
    n=read();m=read();p=read();q=read();
    for(int i=1;i<=p;i++){int x=read();f[x]++;}
    memset(dis,0x3f,sizeof(dis));
    for(int i=1;i<=n;i++)dis[i][i]=0;
    for(int i=1;i<=m;i++){
        int u=read(),v=read(),w=read();dis[u][v]=dis[v][u]=min(dis[u][v],w);
    }
    for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    int l=0,r=1731311,ret=-1;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid))r=mid-1,ret=mid;
        else l=mid+1;
    }
    printf("%d\n",ret);
}

 

posted @ 2017-09-04 20:01  zcysky  阅读(450)  评论(0编辑  收藏  举报