Processing math: 100%

CSU 1806 Toll

最短路,自适应Simpson积分。

看了别人的题解才知道有个东西叫自适应Simpson积分。

有这样一个积分公式:baf(x)dxba6[f(a)+4f(a+b2)+f(b)]。这个东西用于计算不方便直接积分的时候的近似积分。

由于直接套公式会与实际有很大偏差,有一个改进:

要求[L,R]的积分,先令m=L+R2,根据上面的公式,求出[L,R]的公式值s0,以及[L,m]的公式值s1[m,R]的公式值s2

如果s0s1+s2很接近,那么可以认为[L,R]的积分就是s0;否则进行递归,分别求[L,m]的积分和[m,R]的积分。

知道了这个东西之后,这题就变成水题了......

复制代码
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-8;
void File()
{
    freopen("D:\\in.txt","r",stdin);
    freopen("D:\\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
    char c = getchar(); x = 0;while(!isdigit(c)) c = getchar();
    while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar();  }
}

int n,m,T;
struct Edge{int u,v,c,d,nx;}e[200];
int h[20],sz;

void add(int u,int v,int c,int d)
{
    e[sz].u=u; e[sz].v=v; e[sz].c=c; e[sz].d=d;
    e[sz].nx=h[u]; h[u]=sz++;
}

double SPFA(double x)
{
    double dis[20]; bool flag[20];
    for(int i=1;i<=n;i++) dis[i]=999999999999.0;
    memset(flag,0,sizeof flag);
    queue<int>Q; flag[1]=1; Q.push(1); dis[1]=0;
    while(!Q.empty())
    {
        int top=Q.front(); Q.pop(); flag[top]=0;
        for(int i=h[top];i!=-1;i=e[i].nx)
        {
            if(dis[top]+e[i].c*x+e[i].d<dis[e[i].v])
            {
                dis[e[i].v]=dis[top]+e[i].c*x+e[i].d;
                if(flag[e[i].v]==0)
                {
                    flag[e[i].v]=1;
                    Q.push(e[i].v);
                }
            }
        }
    }
    return dis[n];
}

double get(double L,double R)
{
    return (R-L)*(SPFA(L)+4*SPFA((L+R)/2)+SPFA(R))/6;
}

double Ans(double L,double R)
{
    double m=(L+R)/2;
    double s0,s1,s2;
    s0=get(L,R); s1=get(L,m); s2=get(m,R);
    if(fabs(s0-(s1+s2))<=eps) return s0;
    else return Ans(L,m)+Ans(m,R);
}

int main()
{
    while(~scanf("%d%d%d",&n,&m,&T))
    {
        memset(h,-1,sizeof h); sz=0;
        for(int i=1;i<=m;i++)
        {
            int u,v,c,d; scanf("%d%d%d%d",&u,&v,&c,&d);
            add(u,v,c,d);
        }
        printf("%.8lf\n",Ans(0,1.0*T)/T);
    }
    return 0;
}
复制代码

 

posted @   Fighting_Heart  阅读(323)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· SQL Server如何跟踪自动统计信息更新?
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
· 分享一个我遇到过的“量子力学”级别的BUG。
· Linux系列:如何调试 malloc 的底层源码
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
阅读排行:
· 对象命名为何需要避免'-er'和'-or'后缀
· JDK 24 发布,新特性解读!
· .NET Core奇技淫巧之WinForm使用Python.NET并打包
· Java24你发任你发,我用Java8
· C# 中比较实用的关键字,基础高频面试题!
历史上的今天:
2015-09-06 HDU 2444 The Accomodation of Students
2015-09-06 HDU 1045 Fire Net
点击右上角即可分享
微信分享提示