首页 > 代码库 > [CSU1806]Toll

[CSU1806]Toll

题目:Toll

传送门:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1806

题目简述:给定n个点m条有向边的有向图,每条边的花费是$b_i * t +d_i$,设f(t)表示给定t的时候1-n的最小花费,求:${\frac{\int_0^T{f(t)dt}}{T}}$

分析:

 (1)f(t)可用最短路求出来。

 (2)积分值可用自适应辛普森积分法计算。

注意:有向图!

代码:

#include <cstdio>
#include <cstring>
const int N=17,QN=17,M=207;
const double EPS=1e-15,INF=1e9;
int n,m;
int size,fi[N];
struct Edge{int to,next;double c,d;}e[M];
void Gadd(int x,int y,double c,double d){
    e[++size].to=y;e[size].c=c;e[size].d=d;e[size].next=fi[x];fi[x]=size;
}
int q[N+10];double dis[N];bool use[N];
double F(double x){
    for(int i=2;i<=n;++i)dis[i]=INF;
    int h=0,t=1;dis[q[t]=1]=0;
    for(int v;h!=t;){
        if((++h)==QN)h=0;use[v=q[h]]=false;
        for(int i=fi[v],u;i;i=e[i].next){
            u=e[i].to;
            if(dis[v]+e[i].c*x+e[i].d<dis[u]){
                dis[u]=dis[v]+e[i].c*x+e[i].d;
                if(use[u])continue;
                if((++t)==QN)t=0;use[q[t]=u]=true;
            }
        }
    }
    return dis[n];
}
double Simpson(double l,double r){
    return (r-l)*(F(l)+4*F((l+r)/2)+F(r))/6;
}
double Abs(double x){return x<0?-x:x;}
double Integral(double l,double r,double S){
    double mid=(l+r)/2;
    double A=Simpson(l,mid);
    double B=Simpson(mid,r);
    if(Abs(A+B-S)<EPS)
        return S;else return Integral(l,mid,A)+Integral(mid,r,B);
}
int main(){
    for(double T,ans;~scanf("%d%d%lf",&n,&m,&T);){
        size=0;memset(fi,0,sizeof fi);
        for(int i=1,a,b,c,d;i<=m;++i){
            scanf("%d%d%d%d",&a,&b,&c,&d);
            Gadd(a,b,(double)c,(double)d);
        }
        ans=Integral(0,T,Simpson(0,T))/T;
        printf("%.8f\n",ans);
    }
    return 0;
} 

 

[CSU1806]Toll