HDU-6331Problem M. Walking Plan(dp,floyd)

题目:一个有向图,q组询问,每组询问(x,y,z)问从x到y至少经过z条路时的最短路径。

思路:

w[i][j]表示从i到j恰好经过1条路径的最短长度(就是原图)。 
dpa[t][i][j]表示从i到j恰好经过t条路径的最短长度。 
dpb[t][i][j]表示从i到j恰好经过100∗t条路径的最短长度。 
最后floyd来更新dpb数组得到至少经过100∗t条道路的最短路. 
ans=min(dpb[k/100][x][i]+dpa[k%100][i][y]);

#include<bits/stdc++.h>
using namespace std;
int w[55][55],tmp[55][55];
int dpa[110][55][55],dpb[110][55][55];
int n,m;
int dis[55][55];
void solve(int a[][55],int b[][55],int ans[][55])
{
    memset(dis,0x3f,sizeof dis);
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dis[i][j]=min(dis[i][j],a[i][k]+b[k][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            ans[i][j]=dis[i][j];
}
int T,q;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        memset(w,0x3f,sizeof w);
        int inf=w[0][0];
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            w[x][y]=min(w[x][y],z);///可能有重边
        }
        memset(dpa,0x3f,sizeof dpa);
        memset(dpb,0x3f,sizeof dpb);
        for(int i=1;i<=n;i++)
            dpa[0][i][i]=dpb[0][i][i]=0;
        memcpy(dpa[1],w,sizeof dpa[1]);
        for(int i=2;i<=100;i++)
            solve(dpa[i-1],w,dpa[i]);
        memcpy(dpb[1],dpa[100],sizeof dpb[1]);
        for(int i=2;i<=100;i++)
            solve(dpb[i-1],dpa[100],dpb[i]);

        for(int i=1;i<=n;i++)
            w[i][i]=0;
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    w[i][j]=min(w[i][j],w[i][k]+w[k][j]);
        for(int t=0;t<=100;t++)
        {
            memset(tmp,0x3f,sizeof tmp);
            for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                tmp[i][j]=min(tmp[i][j],dpb[t][i][k]+w[k][j]);
            for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dpb[t][i][j]=min(dpb[t][i][j],tmp[i][j]);
        }
        scanf("%d",&q);
        while(q--)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            int ans=inf;
            for(int i=1;i<=n;i++)
            {
                //printf("%d    %d\n",dpb[z/100][x][i],dpa[z%100][i][y]);
                ans=min(ans,dpb[z/100][x][i]+dpa[z%100][i][y]);
            }
            if(ans==inf) puts("-1");
            else printf("%d\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dllpXFire/article/details/81385805