P1220 关路灯区间dp

做了不少dp,这个题一眼就看出是区间dp来了,不过推了一段时间发现不知道怎么推出状态,最后还是看了题解。这个题是从一个区间的左右两边向这个区间来推。

详细解释看代码吧

// let me get FY

#include
#include
#include
#include

using namespace std;

const int maxn = 110;

int a[maxn]; //存位置
int b[maxn]; // 存功率
int sum[maxn]; // 存前几个灯的总功率
int dp[maxn][maxn][2]; // dp区间和两个状态,一个是关完这个区间灯人在左边,另一个是关完这
//个区间灯人在右边

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    memset(dp, 0x3f, sizeof(dp));
    for(int i = 1; i <= n; i++)
    {
        scanf("%d%d",&a[i], &b[i]);
        sum[i] = sum[i - 1] + b[i];
       // printf("%d\n", sum[i]);
    }
    dp[m][m][0] = dp[m][m][1] = 0;
    for(int l = 2; l <= n; l++) // 区间长度
    {
        for(int i = 1; i <= n - l + 1; i++)
        {
            int j = l + i - 1;
           // printf("%d\n", sum[i] + sum[n] - sum[j]);
            dp[i][j][0] = min(dp[i + 1][j][0] + (a[i + 1] - a[i])* (sum[i] + (sum[n] - sum[j])), dp[i + 1][j][1] + (a[j] - a[i]) * (sum[i] + (sum[n] - sum[j])));
            dp[i][j][1] = min(dp[i][j - 1][0] + (a[j] - a[i]) * (sum[i - 1] + (sum[n] - sum[j - 1])), dp[i][j - 1][1] + (a[j] - a[j - 1]) * (sum[i - 1] + (sum[n] - sum[j - 1])));
// 对于关这个区间的灯有两种关法, 关左边和关右边,关左边有两种递推状态,一个是上一个区间
//关灯结束在左边,直接去关这个灯,另一个是在这个区间的右边,折返回来关这个灯,关右边同理
        }
    }
    int ans = min(dp[1][n][0], dp[1][n][1]); // 最后可能的两种状态取最小值
    printf("%d\n", ans);
    return 0;
}

你可能感兴趣的:(dp,区间dp)