旅行计划「分块优化」

题解

第一次遇到这种思路,觉得需要写一写

暴力的话就是直接dp

$f[x][y][j]$表示从x走到y走恰好j步最少路径长度

转移$f[x][y][i]=min(f[x][j][i-1]+edg[j][y])$

因为要至少j步,我们求出来恰好j步然后维护后缀最小值即可

期望得分$10-40$

正解是分块

同样维护$f[x][y][j]$同样维护从x走到y恰好j步最少路径长度,

多维护$f2[x][y][j]$表示走$100*j$步方案数

转移$f2[x][y][j]=min(f[x][j][100]+f2[j][y][j-1])$

然后再维护$f3$是至少$j$步(即$f$数组后缀最小值)

这样回答是$min(f2[x][j][i/100]+f3[j][y][i {Huge \%}100])$

$O(n)$回答

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 55
ll n,m,tot,tot2,qq,s,t,pla;
ll edg[A][A],f[A][A][111],f2[A][A][111];
int main(){
//    freopen("da.in","r",stdin);
//    freopen("ans.bf","w",stdout);
    scanf("%lld%lld",&n,&m);
    memset(edg,0x3f,sizeof(edg));
    for(ll i=1;i<=m;i++){
        ll a,b,c;
        scanf("%lld%lld%lld",&a,&b,&c);
        edg[a][b]=min(c,edg[a][b]);
    }
    memset(f,0x3f,sizeof(f));
    memset(f2,0x3f,sizeof(f2));
    for(ll k=1;k<=n;k++)
        f[k][k][0]=0;
    for(ll q=1;q<=101;q++)
        for(ll i=1;i<=n;i++)
            for(ll k=1;k<=n;k++)
                for(ll j=1;j<=n;j++)
                    f[i][j][q]=min(f[i][k][q-1]+edg[k][j],f[i][j][q]);
    for(ll k=1;k<=n;k++)
        for(ll k2=1;k2<=n;k2++)
            f2[k][k][0]=0,f2[k][k2][1]=f[k][k2][100];
    for(ll q=2;q<=101;q++)
        for(ll k=1;k<=n;k++)
            for(ll i=1;i<=n;i++)    
                for(ll j=1;j<=n;j++){
                f2[i][j][q]=min(f[i][k][100]+f2[k][j][q-1],f2[i][j][q]);
//                if(q<=2)
//                printf("f2[%lld][%lld][%lld]=%lld f[%lld][%lld][%lld]=%lld
",i,j,q,f2[i][j][q],i,j,100ll,f[i][j][100]);
            }
    for(ll q=100;q>=0;q--)
        for(ll i=1;i<=n;i++)
            for(ll j=1;j<=n;j++)        
                f[i][j][q]=min(f[i][j][q+1],f[i][j][q]);
    scanf("%lld",&qq);
    for(ll i=1;i<=qq;i++){
        scanf("%lld%lld%lld",&s,&t,&pla);

        ll ans=123456789101112;
        for(ll j=1;j<=n;j++){
            ans=min(f2[s][j][pla/100]+f[j][t][pla%100],ans);
//        printf("f2[%lld][%lld][%lld]=%lld f[%lld][%lld][%lld]=%lld
",s,j,pla/100,f2[s][j][pla/100],j,t,pla%100,f[j][t][pla%100]);
        }
        if(ans==123456789101112) printf("-1
");
        else printf("%lld
",ans);
    }
}
View Code
原文地址:https://www.cnblogs.com/znsbc-13/p/11733084.html