zoukankan      html  css  js  c++  java
  • 旅行计划「分块优化」

    题解

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

    暴力的话就是直接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
  • 相关阅读:
    透明度问题解决方案
    不得不去奋斗的原因
    未来的你肯定会感谢现在努力的你
    前端学习参考
    js仿京东轮播图效果
    hyper容器网络相关源码分析
    利用setns()将进程加入一个新的network namespace
    frakti && RunPodSandbox 源码分析
    Makefile 编写 tips
    《In Search of an Understandable Consensus Algorithm》翻译
  • 原文地址:https://www.cnblogs.com/znsbc-13/p/11733084.html
Copyright © 2011-2022 走看看