题意
给一个有向图,n<=10个点m条边,第i条边连接< ai,bi>,权值随时间t变化为ci*t+di。设t时刻最短路为f(t),求∫_0^T▒f(t)dt/T。
思路
边权是一次函数,最短路f(t)一定是一些线段组成的函数。理想情况是按照拐点划分,然后分段积分。这里如果区间中点等于左右端点的平均值那么就可以认为这里是一条直线,不必继续划分。而拐点数和点数同一规模,所以这样可以划分到很高的精度。因为被积函数是由一次函数连接的,所以不必用普通辛普森公式的二次拟合,直接用梯形算就好了。
AC代码 C
#include <stdio.h>
#include <string.h>
#include <math.h>
#define MAXN 12
#define INF 1e10
int n;
int G[MAXN][MAXN][2];
double forigin(double x)
{
int i, j, k;
static double dist[MAXN][MAXN];
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
dist[i][j] = G[i][j][0] < 0 ? INF : (double)G[i][j][0] * x + (double)G[i][j][1];
for (k = 1; k <= n; k++)
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
if (dist[i][j] > dist[i][k] + dist[k][j])
dist[i][j] = dist[i][k] + dist[k][j];
return dist[1][n];
}//由forigin(x)得到某点被积函数的值
#define EPS 1e-8 //精度
double simpson(double l, double fl, double r, double fr) //辛普森自适应积分
{
double m = (l + r) * 0.5, fm = forigin(m); //二分中点及其值
return fabs(fl + fr - 2.0 * fm) < EPS ? fm * (r - l) : simpson(l, fl, m, fm) + simpson(m, fm, r, fr);
}//return那句的判断可以根据被积函数的特点改写
int main()
{
int m, T, a, b, c, d;
while (scanf("%d%d%d", &n, &m, &T) > 0)
{
memset(G, -1, sizeof G);
while (m-- && scanf("%d%d%d%d", &a, &b, &c, &d) > 0)
{
G[a][b][0] = c;
G[a][b][1] = d;
}
printf("%.8f\n", simpson(0, forigin(0), T, forigin(T)) / (double)T);
}
return 0;
}