• 【LibreOJ】#539. 「LibreOJ NOIP Round #1」旅游路线


    【题意】给定正边权有向图,车油量上限C,每个点可以花费pi加油至min(C,ci),走一条边油-1,T次询问s点出发带钱q,旅行路程至少为d的最多剩余钱数。

    n<=100,m<=1000,C<=10^5,q<=n^2

    【算法】动态规划

    【题解】官方题解

    虽然不是DAG,但是由于q很小的特点,将q加入状态就满足DP的无后效性了。

    令f[i][q]表示当前在i点并在i点加油,加油前钱数为q的最大路程。(q<pi时,f[i][q]=0)

    假设下一加油点为j,转移方程:f[i][q]=max{f[j][q-pi]+w(i,j,ci)},其中w(i,j,c)表示i点到j点,油量为c的最大路程。(ci=min(ci,C))

    现在主要问题是预处理w(i,j,ci),发现每走一条边c只会减少1,符合倍增变化规则一致的特点,考虑图上倍增。

    虽然不是DAG,但是c加入状态就满足DP的无后效性了。

    g(i,j,k)表示i点到j点,油量为2^k的最大路程,显然g(i,j,k)=max{g(i,x,k-1)+g(x,j,k-1)},x是中转点。

    对于w(i,j,ci),将ci拆分二进制,每次枚举x作为中转点后直接取倍增数组g计算答案。

    【倍增的思想是很经典的,将需要的ci拆分二进制后将1的位用倍增数组堆起来。但是应用到图上每次就都需要遍历全图作为可能的中转点,最后找到最优答案。】

    最后得到了f[i][q],对每个询问在f[s]上二分到第一个大于等于d的f[s][q],q就是答案。

    复杂度O(n^4+n^3*log k+T*log n^2),瓶颈复杂度O(n^4)。(n^4过100……)

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cctype>
    using namespace std;
    int read(){
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    const int maxn=110,maxm=1010,maxk=30,inf=0x3f3f3f3f;
    int n,m,C,T,tot;
    int g[maxn][maxn][maxk],p[maxn],c[maxn],A[maxn],B[maxn],w[maxn][maxn],f[maxn][maxn*maxn];
    void cmax(int &a,int b){if(b>a)a=b;}
    int main(){
        n=read();m=read();C=read();T=read();
        for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)for(int k=0;k<=20;k++)g[i][j][k]=-inf;
        for(int i=1;i<=n;i++)p[i]=read(),c[i]=min(C,read()),g[i][i][0]=0;
        for(int i=1;i<=m;i++){
            int u=read(),v=read(),w=read();
            g[u][v][0]=w;
        }
        for(int k=1;k<=17;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    for(int x=1;x<=n;x++)cmax(g[i][j][k],g[i][x][k-1]+g[x][j][k-1]);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)A[j]=-inf;A[i]=0;
            for(int k=0;k<=17;k++)if((c[i]>>k)&1){
                for(int j=1;j<=n;j++){
                    B[j]=-inf;
                    for(int x=1;x<=n;x++)cmax(B[j],A[x]+g[x][j][k]);
                }
                for(int j=1;j<=n;j++)A[j]=B[j];
            }
            for(int j=1;j<=n;j++)w[i][j]=A[j];
        }
        for(int q=0;q<=n*n;q++)
            for(int x=1;x<=n;x++)if(q>=p[x])
                for(int y=1;y<=n;y++)cmax(f[x][q],f[y][q-p[x]]+w[x][y]);
        while(T--){
            int s=read(),q=read(),d=read();
            int pl=lower_bound(f[s],f[s]+n*n+1,d)-f[s];
            if(pl>q)printf("-1
    ");else printf("%d
    ",q-pl);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Git初探
    ERROR:column &quot;rolcatupdate&quot; does not exist
    Android Studio SVN使用和VisualSVN-Server配置(图解)
    你了解实时计算吗?
    AndroidAnnotations使用说明书—AndroidAnnotations是怎样工作的?
    ios_webView
     paip.android环境搭建与开发事例
    【转】JNI学习积累之一 ---- 常用函数大全
    【转】NI语法 JNI参考 JNI函数大全
    【转】Android 学习笔记——利用JNI技术在Android中调用、调试C++代码
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7791795.html
Copyright © 2020-2023  润新知