sicily 1419(动态规划)

题目链接:sicily 1419

解题思路:(一道稍微有点不一样的动态规划题目)

刚开始看到题目就立马想到一种动规的解法,用dp[i][j]表示第 i 个到达第 j 个点,可是这种做法有一个问题——推导下一个点的时候需要用到再上一个点的数据(因为越慢送的牛奶需要花费越多时间),这样时间复杂度就会达到o( n^3 ),必然超时,于是我们可以看出,要解这道题,要解决两个问题:

1)首先要搜遍所有的数据可能性;2)可以求得最终的总时间

这两个问题,想了好久,发现自己傻逼了……

1)为了使总时间最小,那么只要经过那个点必然就会放下牛奶,所以(假设当前送到了第 i+1 家)第 i 家必然是从第 L 层上来的离 i+1 最近的一家或者另一头的某一家,这样的话并没有n种情况啊,只有L层之下的那些,还有离 i 最近的一个;

2)最终的总时间,因为当前的时间会对后来的时间产生影响,所以(假设从当前点走到下一个点的距离为d,剩余x个点)最后总时间会增加 d*x;(嗯,这样就够了)

最终解法:

首先把所有的楼层(包括L)排一下序,然后用dp[i][j]表示区间 i ~ j 的最短时间(第 i 个点到第 j 个点),不过,还不够,因为终点不同,对后续移动的影响也不同,所以我们需要两个dp数组来记录(dp[0]和dp[1],0代表终点在L下面,1则相反),然后状态转移方程为:

dp[0][i][j]=min(dp[0][i+1][j]+(a[i+1]-a[i])(n-j+i) , dp[1][i+1][j]+(a[j]-a[i])(n-j+i));

dp[1][i][j]=min(dp[1][i][j-1]+(a[j]-a[j-1])(n-j+i) , dp[0][i][j-1]+(a[j]-a[i])(n-j+i));

其中,i < index , j > index(index为L的索引)

代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f

using namespace std;

int n,L,a[1005],dp[2][1005][1005];

int main()
{
    int T,index;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&L);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        a[n++]=L,index=0;
        sort(a,a+n);

        while(index<n)
        {
            if(a[index]==L)
                break;
            index++;
        }

        memset(dp,INF,sizeof(dp));
        dp[0][index][index]=dp[1][index][index]=0;
        for(int i=index;i>=0;i--)
        {
            for(int j=index;j<n;j++)
            {
                if(i<index)
                    dp[0][i][j]=min(dp[0][i+1][j]+(a[i+1]-a[i])*(n-j+i),
                        dp[1][i+1][j]+(a[j]-a[i])*(n-j+i));
                if(j>index)
                    dp[1][i][j]=min(dp[1][i][j-1]+(a[j]-a[j-1])*(n-j+i),
                        dp[0][i][j-1]+(a[j]-a[i])*(n-j+i));
            }
        }
        printf("%d\n",min(dp[0][0][n-1],dp[1][0][n-1]));
    }

    return 0;
}

总结:

1、有点难度的题,重在状态的考虑;

2、动规还是不够熟悉,害得多加练习。

时间: 2025-01-02 17:24:03

sicily 1419(动态规划)的相关文章

编程题目分类(剪辑)

1. 编程入门 2. 数据结构 3. 字符串 4. 排序 5. 图遍历 6. 图算法 7. 搜索:剪枝,启发式搜索 8. 动态规划/递推 9. 分治/递归 10. 贪心 11. 模拟 12. 算术与代数 13. 组合问题 14. 数论 15. 网格,几何,计算几何 [编程入门] PC 110101, uva 100, The 3n+1 problem, 难度 1 PC 110102, uva 10189, Minesweeper, 难度 1 PC 110103, uva 10137, The T

sicily 1176 (动态规划)

题目连接:sicily 1176 解题思路: 题目看上去像是一道博弈的题,又像是一道区间型DP的题目(矩阵取数),而它跟矩阵取数的区别就是他是两个人在取数,所以每次对一个区间,我们应分两种情况考虑:第一个人取左边的数和取右边的数,而在分别考虑这两种情况时,我们又要根据贪心法则来获取上一个取数的区间.状态方程有点复杂,直接上代码了: // Problem#: 1176 // Submission#: 3601655 // The source code is licensed under Crea

sicily 1176. Two Ends (Top-down 动态规划+记忆化搜索 v.s. Bottom-up 动态规划)

DescriptionIn the two-player game "Two Ends", an even number of cards is laid out in a row. On each card, face up, is written a positive integer. Players take turns removing a card from either end of the row and placing the card in their pile. T

sicily 1176 two ends 动态规划解题

1176. Two Ends Constraints Time Limit: 1 secs, Memory Limit: 64 MB Description In the two-player game "Two Ends", an even number of cards is laid out in a row. On each card, face up, is written a positive integer. Players take turns removing a c

sicily 1264(动态规划)

题目链接:sicily 1264 解题思路: 状态挺好想的(详见代码),但是得看透这题计算时间开销的本质--预处理,把所有时间开销的可能性处理处理,剩下的就简单了~ 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n,a[105],r; double b,v,e,f,dis[10005],dp[

sicily 13602(动态规划)

题目链接: sicily 13602 拿到题目马上就想到动规了,而且应该算是棋盘型的DP,状态转移方程挺好想的,就直接上代码了: #include <bits/stdc++.h> using namespace std; long long dp[35][35]; //注意数据范围 int main() { int n; while(~scanf("%d",&n)&&n) { dp[0][0]=1; for(int i=1;i<=n;i++)

bzoj 1419 Red is good - 动态规划 - 概率与期望

Description 桌面上有R张红牌和B张黑牌,随机打乱顺序后放在桌面上,开始一张一张地翻牌,翻到红牌得到1美元,黑牌则付出1美元.可以随时停止翻牌,在最优策略下平均能得到多少钱. Input 一行输入两个数R,B,其值在0到5000之间 Output 在最优策略下平均能得到多少钱. Sample Input 5 1 Sample Output 4.166666 HINT 输出答案时,小数点后第六位后的全部去掉,不要四舍五入. (题目太简洁,不需要大意) 这道题和poj的Collecting

Sicily 1146:Lenny&#39;s Lucky Lotto(dp)

题意:给出N,M,问有多少个长度为N的整数序列,满足所有数都在[1,M]内,并且每一个数至少是前一个数的两倍.例如给出N=4, M=10, 则有4个长度为4的整数序列满足条件: [1, 2, 4, 8], [1, 2, 4, 9], [1, 2, 4, 10], [1, 2, 5, 10] 分析:可用动态规划解题,假设dp[i][j],代表满足以整数i为尾数,长度为j的序列的个数(其中每一个数至少是前一个数的两倍).那么对于整数i,dp[i][j] 等于所有dp[k][j-1]的和,其中k满足:

sicily 1219(记忆化搜索)

题目链接:sicily 1214 解题思路: 博弈题,用搜索来做.但是,如果用普通的搜索来做的话,是会超时的--复杂度大约是O( n^n ),所以需要采用记忆化搜索的方法(其实差不多就是动态规划了,但是这里是树形DP). 状态: 用集合S表示现在树的状态,i 表示现在轮到谁进行砍边,dp[ S ][ i ]表示最优值.集合S可以用二进制来表示,即001表示现在还剩下第0条边. 状态转移: 1)A的目标是取最大值,B的目标是取最小值,我们在推导当前状态的最优解时,需要分两种情况考虑!即A得维护较大