CSU 1806 Toll

13 篇文章 0 订阅
1 篇文章 0 订阅

Description

 In ICPCCamp, there are  cities and  unidirectional roads between cities. The  i-th road goes from the a i-th city to the b i-th city. For each pair of cities  and  v, there is at most one road from  to  v.
As traffic in ICPCCamp is becoming heavier, toll of the roads also varies. At time  t, one should pay (c i⋅t+d i) dollars to travel along the  i-th road.
Bobo living in the 1-st city would like to go to the n-th city. He wants to know the average money he must spend at least if he starts from city 1 at  t∈[0,T]. Note that since Bobo's car is super-fast, traveling on the roads costs him  no time.
Formally, if  f(t) is the minimum money he should pay from city 1 to city  at time  t, Bobo would like to find

Input

The first line contains 3 integers n,m,T (2≤n≤10,1≤m≤n(n-1),1≤T≤10 4).
The i-th of the following m lines contains 4 integers a i,b i,c i,d i (1≤a i,b i≤n,a i≠b i,0≤c i,d i≤10 3).
It is guaranteed that Bobo is able to drive from city 1 to city n.

Output

 A floating number denotes the answer. It will be considered correct if its absolute or relative error does not exceed 10 -6.

Sample Input

3 3 2
1 2 1 0
2 3 1 0
1 3 1 1
3 3 2
1 2 1 0
2 3 1 0
1 3 0 5

Sample Output

1.75000000

2.00000000

有一个积分公式,看似很难的题。

稍微分析一下,其实可以发现,因为c和d是非负整数,显然,从1到n的花费只会随时间增加而增加。

并且,可以发现,对于同一时间,我们会优先选择通过路上∑ci较小的路,因为∑di是不会随时间变动的。

于是,可以以∑ci分段,对于同一段里,∑ci和∑di一定是相同的,

这一段的积分就是(r-l)*((r+l)/2)*∑ci+∑di),最后加起来除于t即可。

#include<set>
#include<map>
#include<ctime>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define rep(i,j,k) for (int i = j; i <= k; i++)
#define per(i,j,k) for (int i = j; i >= k; i--)
#define loop(i,j,k) for (int i = j;i != -1; i = k[i])
#define lson x << 1, l, mid
#define rson x << 1 | 1, mid + 1, r
#define ff first
#define ss second
#define mp(i,j) make_pair(i,j)
#define pb push_back
#define pii pair<int,int>
#define in(x) scanf("%d", &x);
using namespace std;
typedef long long LL;
const int low(int x) { return x&-x; }
const double eps = 1e-8;
const int INF = 0x7FFFFFFF;
const int mod = 1e9 + 7;
const int N = 15;
int n, m, t, x, y;
int c[N][N], d[N][N];
double dis[N];
int u[N], v[N], vis[N];

pii check(double t)
{
	rep(i, 1, n) dis[i] = -1, u[i] = v[i] = vis[i] = 0;
	dis[1] = 0;
	while (true)
	{
		x = 0;
		rep(i, 1, n)
		{
			if (dis[i] < 0 || vis[i]) continue;
			if (!x || dis[i] < dis[x]) x = i;
		}
		if (!x) break; vis[x] = 1;
		rep(i, 1, n)
		{
			if (c[x][i] == -1) continue;
			if (dis[i]<0 || dis[i] - eps > dis[x] + t*c[x][i] + d[x][i])
			{
				dis[i] = dis[x] + t*c[x][i] + d[x][i];
				u[i] = u[x] + c[x][i];
				v[i] = v[x] + d[x][i];
			}
			else if (fabs(dis[x] + t*c[x][i] + d[x][i] - dis[i]) < eps)
			{
				if (u[i] > u[x] + c[x][i])
				{
					u[i] = u[x] + c[x][i];
					v[i] = v[x] + d[x][i];
				}
			}
		}
	}
	return mp(u[n], v[n]);
}

int main()
{
	while (scanf("%d%d%d", &n, &m, &t) != EOF)
	{
		memset(c, -1, sizeof(c));
		while (m--)
		{
			scanf("%d%d", &x, &y);
			scanf("%d%d", &c[x][y], &d[x][y]);
		}
		double l = 0, r = t, ans = 0;
		pii bef = check(l);
		while (l + eps < r)
		{
			double q = l, h = r;
			pii now;
			while (q + eps < h)
			{
				now = check((q + h) / 2);
				if (now.ff == bef.ff) q = (q + h) / 2;
				else h = (q + h) / 2;
			}
			ans += (h - l) * ((h + l) / 2 * bef.ff + bef.ss);
			bef = check(l = h);
		}
		printf("%.8lf\n", ans / t);
	}
	return 0;
}

去翻了翻网上的题解,看到的全是simpson求积分,吓得我赶紧去学了一发,原来还有这么好用的东西。
#include<set>
#include<map>
#include<ctime>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define rep(i,j,k) for (int i = j; i <= k; i++)
#define per(i,j,k) for (int i = j; i >= k; i--)
#define loop(i,j,k) for (int i = j;i != -1; i = k[i])
#define lson x << 1, l, mid
#define rson x << 1 | 1, mid + 1, r
#define ff first
#define ss second
#define mp(i,j) make_pair(i,j)
#define pb push_back
#define pii pair<int,int>
#define in(x) scanf("%d", &x);
using namespace std;
typedef long long LL;
const int low(int x) { return x&-x; }
const double eps = 1e-8;
const int INF = 0x7FFFFFFF;
const int mod = 1e9 + 7;
const int N = 15;
int n, m, t, x, y;
int c[N][N], d[N][N];
double dis[N];
int vis[N];

double get(double t)
{
	rep(i, 1, n) dis[i] = -1, vis[i] = 0;
	dis[1] = 0;
	while (true)
	{
		x = 0;
		rep(i, 1, n)
		{
			if (dis[i] < 0 || vis[i]) continue;
			if (!x || dis[i] < dis[x]) x = i;
		}
		if (!x) break; vis[x] = 1;
		rep(i, 1, n)
		{
			if (c[x][i] == -1) continue;
			if (dis[i] > eps && dis[i] + eps < dis[x] + t*c[x][i] + d[x][i]) continue;
			dis[i] = dis[x] + t * c[x][i] + d[x][i];
		}
	}
	return dis[n];
}

double simpson(double l, double r)
{
	return (r - l) / 6 * (get(l) + 4 * get((l + r) / 2) + get(r));
}

double solve(double l, double r)
{
	double mid = (l + r) / 2, now = simpson(l, r);
	if (fabs(simpson(l, mid) + simpson(mid, r) - now) < eps) return now;
	return solve(l, mid) + solve(mid, r);
}

int main()
{
	while (scanf("%d%d%d", &n, &m, &t) != EOF)
	{
		memset(c, -1, sizeof(c));
		while (m--)
		{
			scanf("%d%d", &x, &y);
			scanf("%d%d", &c[x][y], &d[x][y]);
		}
		printf("%.8lf\n", solve(0, t) / t);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值