【最短路->DP】SPOJ(ACPC13)[Increasing Shortest Path]题解

来源:互联网 发布:数据有效性设置 编辑:程序博客网 时间:2024/05/22 09:43

题目概述

有一张n个点m条边的图,给出Q个询问,每个询问为x,y,c表示求x->y的最小权值,但要满足如下条件:
1.不能走超过c条边。
2.走过的边的权值必须严格递增(保证给出的边的权值没有重复)。

解题报告

由于我们要满足路径边权递增,所以会想到给所有边按照边权排个序。然后我们依次将边加入图中,这样就可以保证路径边权是递增的。
那么在这个想法的基础上,我们记录f[i][j]表示从起点到达i点走了j条边的最优解,则对于每一条x到y边权为z的边,我们可以这么转移:
f[y][j+1]=min(f[y][j+1],f[x][j]+z)

我们会注意到,由于任意两个点间的路径不能存在环(路径边权递增),所以任意两个点之间的距离至多为n-1,这样我们就把c减小为n了!其实还可以进一步优化,因为询问次数远比n大,所以我们还不如直接预处理所有点作为起点时的f[i][j],这样就比每次询问都处理优秀了。
效率:O(mlog2(m)+n2m+nQ)

示例程序

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=150,maxm=5000;int Q,n,m,te,f[maxn+5][maxn+5][maxn+5],INF;struct Edge {int x,y,z;bool operator < (const Edge &c) const {return z<c.z;};};Edge e[maxm+5];void DP(int st){    f[st][st][0]=0;    for (int i=1;i<=m;i++)    for (int j=0;j<n;j++)        if (f[st][e[i].x][j]!=INF&&f[st][e[i].x][j]+e[i].z<f[st][e[i].y][j+1])            f[st][e[i].y][j+1]=f[st][e[i].x][j]+e[i].z;}int main(){    freopen("program.in","r",stdin);    freopen("program.out","w",stdout);    scanf("%d",&Q);    while (Q--)    {        scanf("%d%d%d",&n,&m,&te);        for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);        sort(e+1,e+1+m);        memset(f,63,sizeof(f));INF=f[0][0][0];        for (int i=1;i<=n;i++) DP(i);        while (te--)        {            int st,gl,c;scanf("%d%d%d",&st,&gl,&c);if (c>n) c=n;            int ans=INF;for (int i=0;i<=c;i++) if (f[st][gl][i]<ans) ans=f[st][gl][i];            if (ans==INF) printf("-1\n"); else printf("%d\n",ans);        }    }    return 0;}
原创粉丝点击