8 Nov 2016 本文阅读量

【CODEVS 1183】泥泞的道路

思路

这道题既不是求路程最优值, 也不是求时间最优值, 而是求速度最优值, 乍一看还以为是最优比率生成树, 感觉难度又太高了, 不像。 仔细想想算算, 是一个隐藏着的二分+SPFA
题目要求的是从起点到终点的速度的最大值, 我们设 ans = 总路程/总时间, 那么确定的一条道路 ans = {s1 + s2 + … + sn} / {t1 + t2 + … + tn}, 对式子变形:
=> ans * {t1 + t2 + … + tn} = {s1 + s2 + … + sn}
=> (ans * t1 - s1) + (ans * t2 - s2) + (ans * tn - sn) = 0
我们以 (ans * tn - sn) 为边权重新构图, 二分答案(速度)ans, 当 ans < {s1 + s2 + … + sn} / {t1 + t2 + … + tn}, 即 (ans * t1 - s1) + (ans * t2 - s2) + (ans * tn - sn) < 0 时, 向上继续二分, 否则向下继续二分.
Check就是跑一遍 SPFA最短路, 当 dis[n] <= 0 成立, 否则不成立.
数据坑爹, 需要要判断负环

/*
* Copyright © Eliot
* Date: 2016-11-08
* Author: Eliot
* QQ: 1161142536
* Description: 建模 + 二分 + SPFA最短路
*/

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;

const int MAX = 101;

int n = 0, temp = 0;
double *pLeft = 0, *pRight = 0;
double Arr[MAX][MAX] = { 0 };

double dis[MAX] = { 0 };
bool IsStack[MAX] = { false };
int Count[MAX] = { 0 };
bool SPFA() {
	queue<int> Q;
	for (int i = 0; i < MAX; i++) dis[i] = 9999999;
	bool IsStack[MAX] = { false };
	int Count[MAX] = { 0 };
	
	Q.push(1);
	IsStack[1] = true;
	dis[1] = 0;
	while (!Q.empty()) {
		int nPoint = Q.front();
		Q.pop();
		IsStack[nPoint] = false;
		for (int i = 1; i <= n; i++) {
			if (dis[nPoint] + Arr[nPoint][i] < dis[i]) {
				dis[i] = dis[nPoint] + Arr[nPoint][i];
				if (!IsStack[i]) {
					Count[i] ++;
					if (Count[i] > 3000) return true;
					IsStack[i] = true;
					Q.push(i);
				}
			}
		}
	}

	if (dis[n] <= 0) {
		return true;
	}
	else {
		return false;
	}
}

int main() {
	int(*pArr_dis)[MAX] = new int[MAX][MAX];
	int(*pArr_time)[MAX] = new int[MAX][MAX];
	pLeft = new double(0);
	pRight = new double(100000);

	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			scanf("%d", &temp);
			pArr_dis[i][j] = temp;
		}
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			scanf("%d", &temp);
			pArr_time[i][j] = temp;
		}
	}

	while (*pRight - *pLeft > 0.0001) {
		double dMid = (*pLeft + *pRight) / 2.0;

		//重新构图
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				Arr[i][j] = pArr_time[i][j] * dMid - pArr_dis[i][j];
			}
		}

		if (SPFA()) {
			*pLeft = dMid;
		}
		else {
			*pRight = dMid;
		}
	}
	printf("%.3f\n", *pLeft);

	pArr_time = 0; pLeft = 0;
	pArr_dis = 0; pRight = 0;
	delete[] pArr_time; delete pLeft;
	delete[] pArr_dis; delete pRight;

	return 0;
}

Tags:
Status:

Share:

Comments: