【JZOJ5771】遨游【二分】【DFS】

版权声明:若希望转载,在评论里直接说明即可,谢谢! https://blog.csdn.net/SSL_ZYC/article/details/82812044

题目大意:

题目链接:https://jzoj.net/senior/#main/show/5771
题目图片:
https://www.z4a.net/images/2018/09/22/Screenshot949650fe938ea13c.png
https://www.z4a.net/images/2018/09/22/Screenshot-11765113419a5a9a4.md.png
https://www.z4a.net/images/2018/09/22/2.md.png
https://www.z4a.net/images/2018/09/22/1.md.png
给出 n n 个省,每个神有自己的折扣 p e r [ i ] per[i] ,每个省有 n u m [ i ] num[i] 个城市。有 m m 条路,每条路连接两个城市 u [ i ] u[i] v [ i ] v[i] ,原价是 w [ i ] w[i] ,但打折后的价格就是 ( p e r [ u [ i ] (per[u[i] 所在城市 ] + p e r [ v [ i ] ]+per[v[i] 所在城市 ] ) × 0.5 ])\times 0.5
如果要从 s s t t 的路程免费,那么就得有打折后价格在 [ L , R ] [L,R] 区间之间的路免费通行。求在 L L 最大的情况下且 R R 尽量小的 L , R L,R


思路:

可以二分 L L R R
二分嵌套二分,第一重二分 L L ,第二重二分 R R
每次二分完 L L 之后,搜索一遍能否只走价格大于 L L 的路到达终点,如果可以,就二分 R R
每次二分 R R 之后,如果搜到可以只走价格大于 L L 且小于 R R 的路线的话,那么久将这一组答案记录下来。
最终输出记录的答案即可。


代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#define N 101000
using namespace std;

int n,m,num,s,t,l1,r1,l2,r2,mid1,mid2,tot,L,R;
int u[N],v[N],pos[N],head[N];
double w[N],per[N];
bool ok,vis[N];

struct edge
{
	int dis,to,next;
}e[N*2];

void add(int from,int to,double dis)
{
	e[++tot].to=to;
	e[tot].dis=dis;
	e[tot].next=head[from];
	head[from]=tot;
}

bool dfs(int x,int l,int r)  //搜索是否有方法可以在限制条件下到达t
{
	if (x==t) return true;
	if (vis[x]) return false;
	vis[x]=1;
	for (int i=head[x];~i;i=e[i].next)
	 if (e[i].dis>=(double)l&&e[i].dis<(double)r)
	  if (dfs(e[i].to,l,r)) return true;
	return false;
}

int main()
{
	memset(head,-1,sizeof(head));
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	 scanf("%d%d%lf",&u[i],&v[i],&w[i]);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&num);
		int x;
		for (int j=1;j<=num;j++)
		{
			scanf("%d",&x);
			pos[x]=i;
		}
	}
	for (int i=1;i<=n;i++)
	 scanf("%lf",&per[i]);
	for (int i=1;i<=m;i++)
	{
	   add(u[i],v[i],(per[pos[u[i]]]+per[pos[v[i]]])/2.0*w[i]*0.01);
	   add(v[i],u[i],(per[pos[u[i]]]+per[pos[v[i]]])/2.0*w[i]*0.01);
	}
	scanf("%d%d",&s,&t);
	l1=0;
	r1=15000;
	while (l1<=r1)  //二分L
	{
		mid1=(l1+r1)/2;
		l2=mid1;
		r2=15000;
		ok=false;
		memset(vis,0,sizeof(vis));
		if (dfs(s,mid1,1e9))
		 while (l2<=r2)  //二分R
		 {
			mid2=(l2+r2)/2;
			memset(vis,0,sizeof(vis));
			if (dfs(s,mid1,mid2))
			{
				ok=true;
				L=mid1;
				R=mid2;
				r2=mid2-1;
			}
			else l2=mid2+1;
		 }
		if (ok) l1=mid1+1;
		 else r1=mid1-1;
	}
	printf("%d %d\n",L,R);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/SSL_ZYC/article/details/82812044
今日推荐