其他分享
首页 > 其他分享> > 题解 CF852D Exploration plan

题解 CF852D Exploration plan

作者:互联网

【题意翻译】

给定一个\(V\) 个点\(E\) 条边的带权无向图,在图上有\(N\) 个人,第\(i\) 个人位于点\(x_ i\) ,一个人通过一条边需要花费这条边的边权的时间。

现在每个人可以自由地走。求最短多少时间后满足结束后有人的节点数\(\geq K\)

\(N,V \leq 500\)

【题目分析】

首先发现V很小,直接用\(Floyd\)跑一遍全源最短路径。

然后考虑如何求时间,这个其实是图论中一个很经典的二分+图论的模型,那么我们可以用一个二分寻找\(mid\),连上所有长度\(\leq mid\)的边,用图论来\(check\)。

接下来就要选择图论使用的模型了。在一个图上,有一些人从一个点走向另一个点,很容易想到网络流中的最大流。由于每个点只要有人就行,那么让每个点向超级汇点\(t\)连一条容量为\(1\)的边,代表这个点对答案能产生\(1\)的流量,从超级源点\(s\)向每个点连一条容量为这个点人数的边,代表这个点能流出等同于这个点人数的流量,然后将\(\leq mid\)的边作为网络中的一条边,容量为\(inf\),跑最大流,判断是否\(\geq K\)。

\(tips:\)

  1. 建图的时候要拆点,拆成入口和出口,不然会出现流量分配的问题
  2. 每次check记得memset
  3. 重边要取最小值

愉快的贴代码时间

#include<bits/stdc++.h>
#define inf 1e15
using namespace std;
int read(){
	int w=0,h=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')h=-h;ch=getchar();}
	while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();}
	return w*h;
}
int n,m,s,t,K,cnt,sum;
int cow[610],barn[610];
int floyd[610][610];
struct Dinic{
	struct node{
		int next,to,cap,flow;
	}edge[3000010];
	int head[10010],num;
	int cur[10010];
	int dist[10010];
	queue<int>q;
	void add(int u,int v,int cap,int flow){
		edge[++num].next=head[u];
		edge[num].to=v;
		edge[num].cap=cap;
		edge[num].flow=flow;
		head[u]=num;
		return;
	}
	void Add(int u,int v,int cap){
		add(u,v,cap,0);
		add(v,u,0,0);
		return;
	}
	bool bfs(){
		memset(dist,0,sizeof(dist));
		dist[s]=1;
		q.push(s);
		while(!q.empty()){
			int u=q.front();
			q.pop();
			for(int i=head[u];i;i=edge[i].next){
				int v=edge[i].to;
				if(!dist[v]&&edge[i].cap>edge[i].flow){
					dist[v]=dist[u]+1;
					q.push(v);
				}
			}
		}
		return dist[t];
	}
	int dfs(int u,int flow){
		if(u==t)return flow;
		int fl=0;
		for(int i=cur[u];i;i=edge[i].next){
			cur[u]=i;
			int v=edge[i].to;
			if(dist[u]+1==dist[v]&&edge[i].cap>edge[i].flow){
				int p=dfs(v,min(flow,edge[i].cap-edge[i].flow));
				if(p){
					edge[i].flow+=p;
					edge[i^1].flow-=p;
					flow-=p;
					fl+=p;
					if(!flow)break;
				}
			}
		}
		if(!fl)dist[u]=0;
		return fl;
	}
	int solve(){
		int flow=0;
		while(bfs()){
			memcpy(cur,head,sizeof(cur));
			int p;
			while(p=dfs(s,1e9))flow+=p;
		}
		return flow;
	}
	void memst(){
		memset(head,0,sizeof(head));
		num=1;
	}
	bool check(int x){
		memst();
		for(int i=1;i<=n;i++)Add(i+n,t,1);
		for(int i=1;i<=n;i++){
			if(cow[i])Add(s,i,cow[i]);
			for(int j=1;j<=n;j++)
				if(floyd[i][j]<=x)
					Add(i,j+n,1e9);
		}
		return solve()>=K;
	}
}ans;
signed main(){
	n=read();m=read();cnt=read();K=read();
	s=0;t=n+n+2;
    memset(floyd,0x3f,sizeof(floyd));
	for(int i=1;i<=cnt;i++)cow[read()]++;
	for(int i=1;i<=n;i++)floyd[i][i]=0;
	for(int i=1;i<=m;i++){
		int u=read(),v=read(),w=read();
		floyd[u][v]=floyd[v][u]=min(floyd[u][v],w);
	}
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				floyd[i][j]=min(floyd[i][j],floyd[i][k]+floyd[k][j]);
	int l=0,r=1731311,res=-1;
	while(l<=r){
		int mid=l+r>>1;
		if(ans.check(mid))r=mid-1,res=mid;
		else l=mid+1;
	}
	printf("%d\n",res);
	return 0;
}

标签:dist,int,题解,cap,flow,edge,Exploration,plan,return
来源: https://www.cnblogs.com/pidan123/p/15507856.html