遨游 9.22模拟赛

题目大意:

N个省M条路,然后每个省有一些城市,M条路连接着两座城市(保证是连通图),有什么省级优惠:连接一个省中的两个城市的路费得到xi%的优惠,连接两个省的路得到(xi% + xj%) / 2的优惠,还有什么国家级优惠,如果这个价格在L—R之间则免费,问L & R的大小

解题思路:

dfs + 二分嵌套
二分出 L & R,判断条件是满足(价格>=L && 价格<R)的情况下可以从S到T,满足则不断将L弄大,否则弄小
R同理

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i, a, b, c) for(register int i = a; b; i = c)
#define r(i, a, b) for (register int i = a; i <= b; i++)
#define f(i, a, b) for (register int i = a; i >= b; i--)

using namespace std;

struct SPFA {
	int to, next;
	double w;
}e[500001];
int cnt, N, M, last[200001], s, t;
int n, QWERTYUIOP, u[200001], v[200001], a[200001];
double w[200001], X[200001];//别管那个QWERTYUIOP

double pt(double x) { return x * 0.01; }//x%
inline void add(int u, int v, double w) {
	e[++cnt].to = v; e[cnt].w = w;
	e[cnt].next = last[u]; last[u] = cnt;
	e[++cnt].to = u; e[cnt].w = w;
	e[cnt].next = last[v]; last[v] = cnt;
}//双向边

bool dfs(int now, int low, int high) {
//dfs判断是否有一条路径上每一条路的路费都 low<=  <high
	if (now == t) return 1;//已经到了
	if (v[now]) return 0;//走过就不走了
	v[now] = 1;//标记
	rep(i, last[now], i, e[i].next)//枚举边
		if (e[i].w >= (double)low && e[i].w < (double)high)
		//判断路费是否满足条件
			if (dfs(e[i].to, low, high)) return 1;
			//接着搜
	return 0;
}

int main() {
	scanf("%d%d", &N, &M);
	r(i, 1, M) scanf("%d%d%lf", &u[i], &v[i], &w[i]);
	r(i, 1, N) {
		scanf("%d", &n);
		r(j, 1, n)
			scanf("%d", &QWERTYUIOP),
			a[QWERTYUIOP] = i;
	}
	r(i, 1, N) scanf("%lf", &X[i]);
	scanf("%d%d", &s, &t);
	r(i, 1, M) {
		double rz = 0;
		if (a[u[i]] != a[v[i]])
			rz = (pt(X[a[u[i]]]) + pt(X[a[v[i]]])) / 2.0 * (double)w[i];
		else rz = pt((double)X[a[u[i]]]) * (double)w[i];
		add(u[i], v[i], rz);//建图
	}
	int L = 0, R = 15000, L1 = 0, R1 = 0, mid1, mid2;
	while (L <= R) {//二分
		mid1 = (L + R) >> 1;
		int l = mid1, r = 15000;
		bool ok = 0;
		memset(v, 0, sizeof(v));//初始化
		if (dfs(s, mid1, 2e5)) {
			while (l <= r) {//嵌套
				memset(v, 0, sizeof(v));//初始化
				mid2 = (l + r) >> 1;
				if (dfs(s, mid1, mid2)) {//判断是否满足条件的路径
					ok = 1;
					L1 = mid1; R1 = mid2;//记录下答案
					r = mid2 - 1;
				} else l = mid2 + 1;
			}
		}
		if (ok) L = mid1 + 1;
		else R = mid1 - 1;//常规二分
	}
	printf("%d %d", L1, R1);
}

猜你喜欢

转载自blog.csdn.net/qq_39798042/article/details/82822243