版权声明:转载无所谓的。。。 https://blog.csdn.net/xuxiayang/article/details/82811980
大意
给定一些城市间的路费,先要找出最大的 ,同时 并且 要最小,使得 到 间经过的城市可以免费
思路
在题目中并没有明确给出所有城市间的路费,因为其还需要考虑优惠的情况,所以我们先预处理所有城市的预处理情况,再分别二分 和 ,中间用 判断能否到达即可
代码
#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);//输出
}