ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 CF852D Exploration plan

2021-11-04 14:00:41  阅读:144  来源: 互联网

标签:dist int 题解 cap flow edge Exploration plan return


【题意翻译】

给定一个\(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有