• Codeforces Ilya and Roads


    http://codeforces.com/contest/313/problem/D

    区间DP

    很好的一道题目,是上周的比赛的题目了现在才补上来

    题意:给一个总区间,下面m个小区间,每个小区间有对应的花费,要求用这些小区间去覆盖总区间(允许有重叠),要求覆盖k个单元(不一定连续,只要k个),问最小花费是多少

    很典型的区间dp问题,不过数据很大,要想想怎么处理

    留意到,总区间长度只有300,但是可供选择的小区间的数目多达10^5个,所以可知很多区间是可以去掉的,相同的区间,我们当然只保留花费最小的,但是除此之外还能怎样再减少小区间的数目呢?

    while(m--)
        {
            int x,y;
            ll c;
            cin >> x >> y >> c;
            for(int i=x; i<=y; i++)
                cost[x][i] = min(cost[x][i],c);
        }

    这样做的原因,在相同dp的原理后就会明白

    但是要注意一点,对于一个小区间【x,y】,只能更新cost[x][x] , cost[x][x+1] , cost[x][x+2] , cost[x][x+3] ……  cost[x][y],去区间的左端不能更改,即不能cost[x+k][]这样的,否则是错误的做法

    定义状态:dp[i][j] , 表示从1到i这段连续的区间内,覆盖了k个单元的最小花费

    状态转移为

    首先初始化 dp[i][j] = dp[i-1][j] , 继承前面i-1个单元的成果

    然后  dp[i][j] = min(dp[i][j] , dp[i-k][j-k] + cost[i-k+1][i]);

    用文字来表达也很直白,覆盖后面的一段连续的区间 [i-k+1][i] (长度也就是k),那么就已经覆盖了k个,目标是覆盖j个,那么还剩下j-k个,这j-k将在哪里被覆盖,就是在[1,i-k]里面被覆盖

    即:【1,i】的区间分成两段[1,i-k]   [i-k+1 , i] , 前面那段,覆盖了j-k个,不一定是连续的,后面那段,覆盖了k个,必定是连续的。 费用就是两段的费用和

    所以能理解为什么前面计算cost数组的时候要哪样计算了吧?

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define N 100010
    #define M 310
    #define INF 300000000010
    typedef long long ll;
    
    ll cost[M][M];
    ll dp[M][M];
    
    int main()
    {
        int n,m,s;
        cin >> n >> m >> s;
        for(int i=0; i<=n; i++)
            for(int j=0; j<=n; j++)
                dp[i][j] = cost[i][j] = INF;
        while(m--)
        {
            int x,y;
            ll c;
            cin >> x >> y >> c;
            for(int i=x; i<=y; i++)
                cost[x][i] = min(cost[x][i],c);
        }
        dp[0][0] = 0;
        for(int i=1; i<=n; i++)
            for(int j=0; j<=i; j++)
            {
                dp[i][j] = dp[i-1][j];
                for(int k=1; k<=j; k++)
                    dp[i][j] = min(dp[i][j] , dp[i-k][j-k] + cost[i-k+1][i]);
            }
        if(dp[n][s] >= INF) dp[n][s] = -1;
        cout << dp[n][s] << endl;
        return 0;
    }
  • 相关阅读:
    数据结构实现时的注意事项
    用编程解决生活中的问题
    用编程解决生活中的问题
    中英文对照 —— 生物学基本概念
    中英文对照 —— 生物学基本概念
    面向对象 —— 对类(class)的理解
    面向对象 —— 对类(class)的理解
    百家姓 —— 特别的姓氏与姓氏的由来
    百家姓 —— 特别的姓氏与姓氏的由来
    英文段子
  • 原文地址:https://www.cnblogs.com/scau20110726/p/3127678.html
Copyright © 2020-2023  润新知