HDU6331&&18多校3M Walking Plan 【分块+DP】

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

Total Submission(s): 633    Accepted Submission(s): 229

 

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.

 

题意:给定一个 n 个点,m 条边的有向图,q 次询问 s 到 t 经过至 少 k 条边的最短路。(2 ≤ n ≤ 50, 1 ≤ m, k ≤ 10000, 1 ≤ q ≤ 100000)

分析:比赛时没有思路,后来看啦题解补啦。由于查询次数和至少经过的边数都比较大,如果提前预处理,复杂度是10000*50*50*50,很明显会超时。每次单独计算消耗时间更多。所以可以采用分块的算法来节省时间。此题的分块是提前预处理出任意两点经过至少100*i和i条边的最小距离(i<=100),这个预处理过程可以用DP来完成。然后每次求解答案时,就可以在O(n)的时间内通过枚举中间点计算出来。(例于,要求1到n至少经过1234条边的最小距离,求枚举点p,1经过至少1200条边和p点到n至少经过34条边的距离和的最小值)

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=110;
const int INF=0x3f3f3f3f;
int d[N][N][N],g[N][N][N],a[N][N],b[N][N]; //d数组存任意两点至少经过100*i条边的最小值
                                           //g数组存任意两点至少经过i条边的最小值
int main()
{
    int TA,n,m,T,u,v,x,y,z,num;
    scanf("%d",&TA);
    while(TA--)
    {
        scanf("%d%d",&n,&m);
        memset(g,0x3f,sizeof(g));
        memset(d,0x3f,sizeof(d));
        for(int i=1; i<=n; i++)
            g[0][i][i]=d[0][i][i]=0;
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            if(g[1][x][y]>z)
                g[1][x][y]=z;
        }
        for(int l=1; l<N; l++)
            for(int i=1; i<=n; i++)
                for(int j=1; j<=n; j++)
                    for(int k=1; k<=n; k++)
                        g[l][i][j]=min(g[l][i][j],g[l-1][i][k]+g[1][k][j]);


        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                d[1][i][j]=g[100][i][j];

        for(int l=1; l<N; l++)
            for(int i=1; i<=n; i++)
                for(int j=1; j<=n; j++)
                    for(int k=1; k<=n; k++)
                        d[l][i][j]=min(d[l][i][j],d[l-1][i][k]+d[1][k][j]);

        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                a[i][j]=i==j?0:g[1][i][j];

        for(int k=1; k<=n; k++)
            for(int i=1; i<=n; i++)
                for(int j=1; j<=n; j++)
                    a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
        for(int l=0; l<N; l++)
        {

            for(int i=1; i<=n; i++)
                for(int j=1; j<=n; j++)
                {
                    b[i][j]=INF;
                    for(int k=1; k<=n; k++)
                        b[i][j]=min(b[i][j],d[l][i][k]+a[k][j]);

                    d[l][i][j]=b[i][j];
                }
        }
          
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d%d",&u,&v,&num);
            x=num/100;
            y=num%100;
            int ans=INF;
            for(int k=1; k<=n; k++)
            {
                ans=min(ans,g[y][u][k]+d[x][k][v]);
            }
            if(INF<=ans)ans=-1;
            printf("%d\n",ans);
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值