• UVA_1025 a Spy in the Metro 有向无环图的动态规划问题


    应当认为,有向无环图上的动态规划问题是动态规划的基本模型之一,对于某个模型,如果可以转换为某一有向无环图的最长、最短路径问题,则可以套用动态规划若干方法解决。

    原题参见刘汝佳紫薯267页。

    在这个题目中,首先将整个模型规划成为有向无环图的模式:
    1,对于某小特工,于j时间处在在第i站,可以成为一个独立的状态,也就是有向无环图的一个节点。

    2,对于每个节点,可能能够走得有三个不同的边——坐火车往左走,进入左边的某个状态;坐火车往右走,进入右边的某个状态;原地等待,进入该站点的下一个时间。

    每条边,拥有权重——坐火车边权位0,但是原地等待边权位1.,由此,可以将动态规划的问题描述成为一个有向无环图上的寻路问题。直觉上至少可以使用最短路算法。

    但是对于有向无环图情况,可以进行特殊的优化:使用直接刷表法求得。

    之前,我们大多使用“对于每个节点进行扫描的时候更新该节点的所有子节点中某值,从而使得,该节点得到最优解”。但是很多时候,并不一定可以使用这种思路来进行很直观的赋值。在这种情况下,我们可以退而求其次,通过若干次计算,在到达某一节点之后“更新”可能直接到达的节点的边权,从而得到,我们需要的最值。

    这道题在做的时候,感觉到有些比较深的坑——例如初始化的故事。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    const long long MAXN=233;
    const long long INF=1e9+233;
    long long n,t,m1,m2;
    long long ti[MAXN];
    long long d1[MAXN];
    long long d2[MAXN];
    bool check[MAXN][MAXN][2];
    long long dp[MAXN][MAXN];
    
    long long ca=1;
    void init()
    {
        memset(check,0,sizeof(check));
        memset(ti,0,sizeof(ti));
        memset(d1,0,sizeof(d1));
        memset(d2,0,sizeof(d2));
        cin>>t;
        for(int i=0;i<n-1;++i)    cin>>ti[i];
        cin>>m1;
        for(int i=0;i<m1;++i)    cin>>d1[i];
        cin>>m2;
        for(int i=0;i<m2;++i)    cin>>d2[i];
        check[0][d1[0]][0]=1;check[n-1][d2[0]][1]=1;
        
        for(int i=0;i<MAXN;++i)
        {
            for(int j=0;j<MAXN;++j)dp[i][j]=INF;
        }long long time=0;
        for(int i=0;i<n-1;++i)
        {
            
            for(int j=0;j<m1;++j)
            {
                check[i][d1[j]+time][0]=1;
    //            cout<<"left: "<<i<<ends<<d1[j]+time<<endl;
            }time+=ti[i];
        }
        time=0;
        for(int i=n-1;i;--i)
        {
            time+=ti[i];
            for(int j=0;j<m2;++j)
            {
                check[i][d2[j]+time][1]=1;
    //            cout<<"right: "<<i<<ends<<d2[j]+time<<endl;
            }
        }dp[0][0]=0;
        for(int j=0;j<=t;++j)
        {
            for(int i=0;i<n;++i)
            {
                if(dp[i][j]>=INF)continue;
                dp[i][j+1]=min(dp[i][j]+1,dp[i][j+1]);
                if(i<n-1&&check[i][j][0])dp[i+1][j+ti[i]]=min(dp[i][j],dp[i+1][j+ti[i]]);//,cout<<"check_left "<<i<<ends<<j<<ends<<dp[i][j]<<endl;
                if(i&&check[i][j][1])dp[i-1][j+ti[i-1]]=min(dp[i][j],dp[i-1][j+ti[i-1]]);//,cout<<"check_right "<<i<<ends<<j<<ends<<dp[i][j]<<endl;
            }
        }
        cout<<"Case Number "<<ca++<<": ";
        if(dp[n-1][t]<INF)cout<<dp[n-1][t]<<"
    ";
        else cout<<"impossible
    ";
        
    }
    
    
    int main()
    {
        cin.sync_with_stdio(false);
        while(cin>>n&&n)init();
        
        return 0;
    }
  • 相关阅读:
    数据存储 twisted
    数据存储 mongodb
    数据存储 redis
    数据存储 txt
    同时使用有线内网与无线外网
    使用xshell从服务器下载文件
    everything使用技巧
    【吴恩达机器学习】第8章 正则化
    python文件重命名
    【统计学习】 第5章 决策树
  • 原文地址:https://www.cnblogs.com/rikka/p/7448262.html
Copyright © 2020-2023  润新知