【校内模拟】分居(最短路)

简要题意:

给一张带权无向连通图,请你确定两个位置,可以在边上,使得这两个位置的之间的最短路最大。

题目给的范围 : n ≤ 1 e 3 , m ≤ 2 e 3 n\leq 1e3,m\leq 2e3 n1e3,m2e3


题解:

写官方题解的人是个傻逼,根本不需要考虑的那么复杂。

而且输入数据比题目给的范围大了将近一倍,造数据的人也是傻逼。

想法非常显然,确定两条边 ( u , v , w 1 ) , ( x , y , w 2 ) (u,v,w_1),(x,y,w_2) (u,v,w1),(x,y,w2),设 t 1 t_1 t1 表示第一个点在 ( u , v ) (u,v) (u,v) 边上与 u u u 的距离, t 2 t_2 t2 表示第二个点在 ( x , y ) (x,y) (x,y) 边上与 x x x 的距离。

a = d i s [ u ] [ x ] , b = d i s [ u ] [ y ] + w 2 , c = d i s [ v ] [ x ] + w 1 , d = d i s [ v ] [ y ] + w 1 + w 2 a=dis[u][x],b=dis[u][y]+w_2,c=dis[v][x]+w_1,d=dis[v][y]+w_1+w_2 a=dis[u][x],b=dis[u][y]+w2,c=dis[v][x]+w1,d=dis[v][y]+w1+w2

那么显然就是要求这个东西:

max ⁡ 0 ≤ t 1 ≤ w 1 , 0 ≤ t 2 ≤ w 2 { min ⁡ ( x + y + a , x − y + b , − x + y + c , − x − y + d ) } \max_{0\leq t_1\leq w_1,0\leq t_2\leq w_2}\{\min(x+y+a,x-y+b,-x+y+c,-x-y+d)\} 0t1w1,0t2w2max{min(x+y+a,xy+b,x+y+c,xy+d)}

于是容易想到分别最大化 min ⁡ ( x + y + a , d − x − y ) \min(x+y+a,d-x-y) min(x+y+a,dxy) 和另外两个。

根据最短路的性质很容易发现 ∣ d − a ∣ ≤ 2 ( w 1 + w 2 ) |d-a|\leq 2(w_1+w_2) da2(w1+w2),同理另一个也可以取到。

随便做就行了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}template<typename T>T get_integer(){
		char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;
		while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;
	}inline int gi(){return get_integer<int>();}
}using namespace IO;

using std::cerr;
using std::cout;
using pii=std::pair<int,int>;
#define fi first
#define se second

cs int N=2e3+7,M=8e3+7;

int n,m;

int el[N],nx[M<<1|1],to[M<<1|1],w[M<<1|1],ec;
inline void adde(int u,int v,int vl){
	nx[++ec]=el[u],el[u]=ec,to[ec]=v,w[ec]=vl;
	nx[++ec]=el[v],el[v]=ec,to[ec]=u,w[ec]=vl;
}

int dis[N][N];bool vs[N];
std::priority_queue<pii,std::vector<pii>,std::greater<pii> > q;
void Dij(int S){
	for(int i=1;i<S;++i)
		q.push(pii(dis[S][i],i));
	q.push(pii(dis[S][S]=0,S));
	for(int re i=1;i<=n;++i)vs[i]=false;
	while(!q.empty()){
		int u=q.top().se;q.pop();
		if(vs[u])continue;vs[u]=true;
		for(int re e=el[u];e;e=nx[e])
			if(dis[S][to[e]]>dis[S][u]+w[e])
				q.push(pii(dis[S][to[e]]=dis[S][u]+w[e],to[e]));
	}for(int re i=S+1;i<=n;++i)dis[i][S]=dis[S][i];
}

void Main(){
	n=gi(),m=gi();ec=0;
	memset(el,0,(n+1)<<2);
	for(int re i=1;i<=m;++i){
		int u=gi(),v=gi();
		adde(u,v,gi());
	}for(int re i=1;i<=n;++i)
		memset(dis[i],0x3f,(n+1)<<2);
	if(m==1)return (void)printf("%.1lf\n",(double)w[1]);
	for(int re i=1;i<=n;++i)Dij(i);
	double ans=0;
	for(int re i=1;i<ec;i+=2)
		for(int re j=i+2;j<ec;j+=2){
			int u=to[i],v=to[i+1];
			int x=to[j],y=to[j+1];
			int w1=w[i],w2=w[j];
			ll a=dis[u][x],b=dis[u][y]+w2;
			ll c=dis[v][x]+w1,d=dis[v][y]+w1+w2;
			ans=std::max(ans,std::min((a+d)*.5,(b+c)*.5));
		}
	printf("%.1lf\n",ans);
}

inline void file(){
#ifdef zxyoi
	freopen("apart.in","r",stdin);
#else
#ifndef ONLINE_JUDGE
	freopen("apart.in","r",stdin);
	freopen("apart.out","w",stdout);
#endif
#endif
}
signed main(){file();int T=gi();while(T--)Main();} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值