2018年9月22日提高组模拟赛 T1 遨游

版权声明:转载无所谓的。。。 https://blog.csdn.net/xuxiayang/article/details/82811980

大意

给定一些城市间的路费,先要找出最大的 L L ,同时 R L R\geq L 并且 R R 要最小,使得 s s t t 间经过的城市可以免费


思路

在题目中并没有明确给出所有城市间的路费,因为其还需要考虑优惠的情况,所以我们先预处理所有城市的预处理情况,再分别二分 L L R R ,中间用 s p f a   ( b f s ) spfa\ (bfs) 判断能否到达即可


代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define N 200001
#define C 50001
using namespace std;int n,m,u[N],v[N],w[N],z,p;
int head[C],fa[C],dis[C],tot,s,t,l1,l2,r1,r2,x[N];
bool vis[C];
double l=15000,r;
struct node{int next,to;double w;}e[N<<1];
inline void add(register int u,register int v,double w){e[++tot]=(node){head[u],v,w};head[u]=tot;return;}
inline int read()//读入优化
{
	int d=1,f=0;char c;
	while(c=getchar(),c<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),c>47&&c<58)f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline bool spfal(register int xz)//spfa判断l是否合法
{
	memset(dis,0x3f,sizeof(dis));//初始化dis数组,用来判断能否到达
	memset(vis,0,sizeof(vis));//防止重复走过
	queue<int>q;q.push(s);
	vis[s]=true;dis[s]=0;
	while(q.size())
	{
		int x=q.front();q.pop();vis[x]=true;
		for(register int i=head[x];i;i=e[i].next)
		{
			int y=e[i].to;double w=e[i].w;
			if(w>=xz&&dis[y]>dis[x]+1)//注意这里比普通的spfa多了一个限制(xz)
			{
				dis[y]=dis[x]+1;
				if(!vis[y]) q.push(y),vis[y]=true;
			}
		}
		vis[x]=false;
	}
	return dis[t]!=0x3f3f3f3f;
}
inline bool spfar(register int xz)//判断在该限制是否能到达t点
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	queue<int>q;q.push(s);
	vis[s]=true;dis[s]=0;
	while(q.size())
	{
		int x=q.front();q.pop();vis[x]=true;
		for(register int i=head[x];i;i=e[i].next)
		{
			int y=e[i].to;double w=e[i].w;
			if(w<=xz&&w>=l1*1.000&&dis[y]>dis[x]+1)//注意同时也要大于等于L
			{
				dis[y]=dis[x]+1;
				if(!vis[y]) q.push(y),vis[y]=true;
			}
		}
		vis[x]=false;
	}
	return dis[t]!=0x3f3f3f3f;
}
signed main()
{
	n=read();m=read();
	for(register int i=1;i<=m;i++)//输入
	{
		u[i]=read();
		v[i]=read();
		w[i]=read();
	}
	for(register int i=1;i<=n;i++)
	{
		p=read();
		while(p--) fa[read()]=i;//标记每个城市对应的省份
	}
	for(register int i=1;i<=n;i++) x[i]=read();//输入优惠值
	s=read();t=read();
	for(register int i=1;i<=m;i++)
	{
		double val=w[i]*(x[fa[u[i]]]+x[fa[v[i]]])*1.000/200;//因为是按百分比算的,所以要除以200
		add(u[i],v[i],val);add(v[i],u[i],val);//建边
		l=min(l,val);r=max(r,val);//最终的优惠价格必定在这些路径的最大最小值之间
	}
	l1=l2=l;r1=r2=r;//初始化
	while(l1<r1)//确定左边界
	{
		int mid=(l1+r1)>>1;
		if(spfal(mid)) l1=mid+1;else r1=mid;//二分
	}
	while(!spfal(l1)) l1--;//判断是否合法,不合法就不断放宽要求,直至合法为止
	l2=l1;//此时的l1即为L,再在L和r2之间继续查找R
	while(l2<r2)//二分
	{
		int mid=(l2+r2)>>1;
		if(spfar(mid)) r2=mid;else l2=mid+1;//二分
	}
	while(!spfar(l2)) l2++;//判断l2是否合法,不合法则放宽要求,直至合法为止
	printf("%d %d",l1,l2);//输出
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/82811980