csu 1806(前向星+spfa+自适应辛普森)

题目链接:

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

题解:

首先先了解下什么是自适应辛普森, 贴一个dalao的博客:http://blog.csdn.net/u014800748/article/details/44343955
此题只要调用一次自适应辛普森公式就可以了,其中f(x)就是当前时间为x时,从点1到点n的最短路,可以用前向星+spfa搞定。

自适应辛普森的模板:

const int eps = 1e-6;
double cal(double l, double r)
{
    return (r-l) * (f(l) + 4 * f((l+r)/2) + f(r))/6;
}
double simpson(double l, double r)
{
    double h = (l+r)/2;
    double s0 = cal(l,r),s1 = cal(l,h),s2 = cal(h,r);
    if(fabs(s0 - (s1+s2)) <= eps)return s0;
    else return simpson(l,h) + simpson(h,r);
}

链式前向星的模板:

struct edge
{
    int to,next,ci,di;//next表示该边连接的下一条边,to表示该边的右结点,可以加额外变量存其他信息
}e[1000];
int head[1000];
int tot;
void add(int u,int v,int c,int d)
{
    e[++tot].to = v;
    e[tot].next = head[u];
    e[tot].ci = c;
    e[tot].di = d;
    head[u] = tot;
}

memset(head,0,sizeof(head));tot=0;//每次计算的清空操作

for(int i = head[u];i;i = e[i].next)//访问以u为起点,所有以该点为起点的边

AC代码:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

const int eps = 1e-6;
int n,m,t;

struct edge
{
    int to,next,ci,di;
}e[1000];
int head[1000];
int tot;
void add(int u,int v,int c,int d)
{
    e[++tot].to = v;
    e[tot].next = head[u];
    e[tot].ci = c;
    e[tot].di = d;
    head[u] = tot;
}
double dist[100];
int vis[100];

double spfa(double x)
{
    for(int i=1;i<=n;i++) dist[i]=999999999999.0;
    memset(vis,0,sizeof(vis));
    dist[1] = 0;
    queue <int> que;
    que.push(1);
    vis[1] = 1;
    while(!que.empty())
    {
        int u = que.front();
        que.pop();
        for(int i = head[u];i;i = e[i].next)
        {
            if(dist[u] + e[i].ci * x + e[i].di < dist[e[i].to])
            {
                dist[e[i].to] = dist[u] + e[i].ci * x + e[i].di;
                if(vis[e[i].to] == 0)
                {
                    vis[e[i].to] = 1;
                    que.push(e[i].to);
                }
            }
        }
        vis[u] = 0;
    }
    return dist[n];
}

double cal(double l, double r)
{
    return (r-l) * (spfa(l) + 4 * spfa((l+r)/2) + spfa(r))/6;
}
double simpson(double l, double r)
{
    double h = (l+r)/2;
    double s0 = cal(l,r),s1 = cal(l,h),s2 = cal(h,r);
    if(fabs(s0 - (s1+s2)) <= eps)return s0;
    else return simpson(l,h) + simpson(h,r);
}



int main()
{
    while(~scanf("%d %d %d",&n, &m, &t))
    {
        memset(head,0,sizeof(head));tot=0;
        for(int i = 0; i < m; i++)
        {
            int a,b,c,d;
            scanf("%d %d %d %d", &a, &b, &c, &d);
            add(a,b,c,d);
        }
        double ans = simpson(0,(double)t)/t;
        printf("%.8f\n", ans);
    }
    return 0;
}

/*
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
*/

你可能感兴趣的:(ACM之路,图论,数学)