2018 Multi-University Training Contest 3 &&HDU6331 Walking Plan【最短路DP】

Walking Plan

Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)

Problem Description

There are n intersections in Bytetown, connected with m one way streets. Little Q likes sport walking very much, he plans to walk for q days. On the i-th day, Little Q plans to start walking at the si-th intersection, walk through at least ki streets and finally return to the ti-th intersection.
Little Q’s smart phone will record his walking route. Compared to stay healthy, Little Q cares the statistics more. So he wants to minimize the total walking length of each day. Please write a program to help him find the best route.

Input

The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases.
In each test case, there are 2 integers n,m(2≤n≤50,1≤m≤10000)
in the first line, denoting the number of intersections and one way streets.
In the next m lines, each line contains 3 integers ui,vi,wi(1≤ui,vi≤n,ui≠vi,
1≤wi≤10000), denoting a one way street from the intersection ui to vi, and the length of it is wi
Then in the next line, there is an integer q(1≤q≤100000) , denoting the number of days. In the next q lines, each line contains 3 integers si,ti,ki(1≤si,ti≤n,1≤ki≤10000) , describing the walking plan.

Output

For each walking plan, print a single line containing an integer, denoting the minimum total walking length. If there is no solution, please print -1.

Examples

Input
2
3 3
1 2 1
2 3 10
3 1 100
3
1 1 1
1 2 1
1 3 1
2 1
1 2 1
1
2 1 1

Output
111
1
11
-1

【题目链接】 Walking Plan

【题意】

给定一个 n个点,m条边的有向图,q 次询问 s 到 t 经过至少 k 条边的最短路。

【思路】

用c[i][j]表示从i经过一条边到j的最短路,a[path][i][j]表示从i恰好经过path条边到j的最短路

那么有转移方程a[path][i][j]=min{a[path-1][i][k]+c[k][j]}

这个转移方程是n3的,k的范围有10000,所以不能直接转移,我们考虑把每个询问s,t,k拆成两部分:

从 s 出发经过恰好 100A 条边到达某个点 u。
从 u 出发经过至少 B 条边到达 t。
然后我们再用a[path][i][j]表示从i恰好经过path*100条边到j的最短路

由于题目要求最少k条边,我们再对b数组跑一次Floyd算法即可

然后令A=k%100,B=k/100,枚举中间点u,答案就是min{a[A][s][u] +b[B][u][t]}。

有点人可能会问,为什么不用对a数组跑Floyd,因为我们b[0][i][j]储存的就是i到j的最短路,我们可以先恰好A步到某一个点,然后走最短路到终点即可,也是大于等于k的

#include <cstdio>
#include <bits/stdc++.h>
#include <cmath>
#include <map>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)

typedef  long long ll;
const int maxn = 55;
const ll mod = 1e9+7;
const int INF = 1e9;
const double eps = 1e-6;

int n,m,q;
int c[maxn][maxn];
int dis[maxn][maxn];
int tmp[maxn][maxn];
int a[105][maxn][maxn];
int b[105][maxn][maxn];

void solve(int a[][maxn],int b[][maxn],int c[][maxn])
{
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    {
        c[i][j]=INF;
        for(int k=0;k<n;k++)
        {
            c[i][j]=min(c[i][j],a[i][k]+b[k][j]);
        }
    }
}

void Floyd()
{
    for(int k=0;k<n;k++)
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    {
        dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    }
}

int main()
{
    rush()
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
            c[i][j]=INF;
            a[0][i][j]=b[0][i][j]=(i==j?0:INF);
        }
        while(m--)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            u--,v--;
            c[u][v]=min(c[u][v],w);
        }
        for(int i=1;i<105;i++) solve(a[i-1],c,a[i]);
        for(int i=1;i<105;i++) solve(b[i-1],a[100],b[i]);
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
            dis[i][j]=(i==j?0:c[i][j]);
        }
        Floyd();
        for(int path=0;path<105;path++)
        {
            for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            {
                tmp[i][j]=INF;
            }
            for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            for(int k=0;k<n;k++)
            {
                tmp[i][j]=min(tmp[i][j],b[path][i][k]+dis[k][j]);
            }
            for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            {
                b[path][i][j]=tmp[i][j];
                //if(path==0) printf("%d %d**%d\n",i+1,j+1,tmp[i][j]);
            }
        }
        scanf("%d",&q);
        while(q--)
        {
            int u,v,k;
            scanf("%d%d%d",&u,&v,&k);
            u--,v--;
            int A=k%100,B=k/100;
            int ans=INF;
            for(int i=0;i<n;i++)
            {
                ans=min(ans,a[A][u][i]+b[B][i][v]);
            }
            if(ans==INF) puts("-1");
            else printf("%d\n",ans);
        }
    }
}
发布了259 篇原创文章 · 获赞 100 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/my_sunshine26/article/details/81320483