51nod1757大灾变
Posted sadstone
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod1757大灾变相关的知识,希望对你有一定的参考价值。
Description
原题链接
有一棵树,树上有些特殊点,每个不是特殊点的点有一个人,每个人走过一条边的时间为1。现在所有的人要走到特殊点上,每个点可以有多个人,但每条边每1时间只能走一个人。求所有人到达特殊点的最小时间。
Solution
考虑每个人应该走向哪个洞穴。假如一个人要到一个洞穴\(a_i\),到达距离为\(d\),把每个洞穴拆成\(n\)个点,如果还没有人要走到这个洞穴的第\(d\)号点,那么这个人可以走到这个点,如果已经被另一个人所走到,则可以匹配该洞穴的下一个点或下一个洞穴。要使所有洞穴被走到编号的最大值最小。
于是可以二分答案,于是转换成判定性问题,网络流或者匈牙利判一下有没有匹配即可。
Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
#define rep(i,x) for(int i=ls[x];i;i=nx[i])
using namespace std;
const int N=2010,maxn=1e5+10,M=4e5+10,inf=1e9;
int to[M],nx[M],ls[maxn],vl[M],num=1;
int S,T;
int a[N];
int n,m;
bool bz[N];
void link(int u,int v,int w){
to[++num]=v,nx[num]=ls[u],ls[u]=num;
vl[num]=w;
to[++num]=u,nx[num]=ls[v],ls[v]=num;
vl[num]=0;
}
vector<int> e[N];
int d[N][N],now;
void dfs(int x,int fr,int t){
d[now][x]=t;
int o=e[x].size();
fo(i,0,o-1) if(e[x][i]!=fr) dfs(e[x][i],x,t+1);
}
int h[maxn],q[maxn];
bool bfs(){
int l=0,r=1;
memset(h,0,sizeof(h));
h[q[1]=S]=1;
while(l<r){
int x=q[++l];
rep(i,x){
if(!vl[i]) continue;
int v=to[i];
if(!h[v]) h[v]=h[x]+1,q[++r]=v;
}
}
return h[T]>0;
}
int flow(int x,int t){
if(x==T) return t;
int fl=t;
rep(i,x){
int v=to[i];
if(!vl[i] || h[v]!=h[x]+1) continue;
int tmp=flow(v,min(t,vl[i]));
t-=tmp,vl[i]-=tmp,vl[i^1]+=tmp;
if(!t) break;
}
if(fl==t) h[x]=-1;
return fl-t;
}
bool check(int x){
memset(ls,0,sizeof(ls));
S=n+x*m+1,T=S+1;
num=1;
fo(i,1,m)
fo(j,1,x){
link(i+n+(j-1)*m,T,1);
if(j<x) link(i+n+(j-1)*m,i+n+j*m,inf);
}
fo(i,1,n) if(!bz[i]){
link(S,i,1);
fo(j,1,m) if(d[i][a[j]]<=x) link(i,j+n+(d[i][a[j]]-1)*m,1);
}
int ans=0;
while(bfs()) ans+=flow(S,inf);
return ans==n-m;
}
int main()
{
scanf("%d %d",&n,&m);
fo(i,2,n){
int u,v;
scanf("%d %d",&u,&v);
e[u].push_back(v),e[v].push_back(u);
}
fo(i,1,n) now=i,dfs(i,0,0);
fo(i,1,m) scanf("%d",&a[i]),bz[a[i]]=1;
int l=1,r=n;
while(l+1<r){
int mid=(l+r)>>1;
check(mid)?r=mid:l=mid;
}
if(check(l)) r=l;
printf("%d\n",r);
}
以上是关于51nod1757大灾变的主要内容,如果未能解决你的问题,请参考以下文章