51nod1757 大灾变

能想到二分答案+最大流判断是否符合。但是不知道如何建图qaq。参考的是http://blog.csdn.net/fsss_7/article/details/52132046的建图方法

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<vector>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
#define qwq(x) for(edge *o=head[x];o;o=o->next)
int read(){
	int x=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
	return x;
}
const int nmax=2e3+5;
const int maxn=2e5+5;
const int inf=0x7f7f7f7f;
struct edge{
	int to,cap;edge *next,*rev;
};
edge es[maxn<<3],*pt=es,*head[maxn];
void add(int u,int v,int d){
	pt->to=v;pt->cap=d;pt->next=head[u];head[u]=pt++;
	pt->to=u;pt->cap=0;pt->next=head[v];head[v]=pt++;
	head[u]->rev=head[v];head[v]->rev=head[u];
}

vector<int>a[nmax];
int dis[50][nmax],in[nmax],on[nmax];
void dfs(int p,int x,int fa){
	int u;
	rep(i,0,a[x].size()-1) if((u=a[x][i])!=fa)
	  dis[p][u]=dis[p][x]+1,dfs(p,u,x);
}

edge *cur[maxn],*p[maxn];
int cnt[maxn],h[maxn];
int maxflow(int s,int t,int n){
	clr(cnt,0);cnt[0]=n;clr(h,0);
	int flow=0,a=inf,x=s;edge *e;
	while(h[s]<n){
		for(e=cur[x];e;e=e->next) if(e->cap>0&&h[x]==h[e->to]+1) break;
		if(e){
			a=min(a,e->cap);cur[x]=p[e->to]=e;x=e->to;
			if(x==t){
				while(x!=s) p[x]->cap-=a,p[x]->rev->cap+=a,x=p[x]->rev->to;
				flow+=a;a=inf;
			}
		}else{
			if(!--cnt[h[x]]) break;
			h[x]=n;
			for(e=head[x];e;e=e->next) if(e->cap>0&&h[x]>h[e->to]+1) h[x]=h[e->to]+1,cur[x]=e;
			cnt[h[x]]++;
			if(x!=s) x=p[x]->rev->to;
		}
	}
	return flow;
}

int check(int x,int n,int m){
	int s=0,t=n+m*x+1;
	pt=es;clr(head,0);
	rep(i,1,n) if(!in[i]) add(s,i,1);
	rep(i,1,m) {
		rep(j,1,x) add(n+(i-1)*x+j,t,1);
		rep(j,1,x-1) add(n+(i-1)*x+j,n+(i-1)*x+j+1,inf);
	}
	rep(i,1,m){
		rep(j,1,n) if(!in[j]&&dis[i][j]<=x) add(j,n+(i-1)*x+dis[i][j],1);
	}
	return maxflow(s,t,t+1);
}
int main(){
	int n=read(),m=read(),u,v;
	rep(i,1,n-1) u=read(),v=read(),a[u].push_back(v),a[v].push_back(u);
	rep(i,1,m) u=read(),in[u]=1,on[i]=u;
	rep(i,1,m) dfs(i,on[i],0);
	int l=0,r=n,mid,ans=0;
	while(l<=r){
		mid=(l+r)>>1;
		if(check(mid,n,m)==n-m) ans=mid,r=mid-1;
		else l=mid+1;
	}
	printf("%d
",ans);
	return 0;
}

  

基准时间限制:3 秒 空间限制:262144 KB 分值: 160 难度:6级算法题
 收藏
 关注
死亡之翼降临了!艾泽拉斯大陆的子民们必须逃出他的魔爪!
艾泽拉斯的结构是一棵树,这棵树上的一些节点是地精建造的通往地下避难所的洞口。
除了这些洞口之外,树上的每个节点上都有一个种族,每个种族通过树上的一条边都需要一个单位时间。
因为地精比较矮小,所以洞口很窄,每个单位时间只能让一个种族通过,但是一个单位时间内的一个节点上可以存在多个种族。
地精们需要你求出最少需要多少单位时间才能让所有种族躲进地下避难所。
【注意题目有修改,洞口不一定是叶子节点】
Input
第1行两个整数n(n<=2000)和m(m<=40)表示节点个数和洞口个数
接下来n-1行每行两个整数表示树上的每一条边
第n+1行m个整数表示所有洞口的编号,保证洞口是叶子节点
Output
一个整数t表示让所有种族躲进地下避难所的最少时间
Input示例
6 2
1 2
1 3
1 4
1 5
5 6
3 6
Output示例
3
原文地址:https://www.cnblogs.com/fighting-to-the-end/p/5862723.html