nyoj304 節能 動態規劃

這個題自己琢磨了好久,也沒想出狀態轉移方程,一經提醒才大悟啊!
這是個區間型DP,先開門見山看一下怎樣存狀態的吧:d[i][j][0] 所存的狀態是在i到j這個區間所有燈已關閉,並且機器人位於i點時所消耗的最小功率。 d[i][j][1]所代表就是 i到j區間所有燈已關閉,位於j點時 所消耗的最小功率。
d[i][j][0] 區間(i, j)的燈都關閉了,機器人正位於i點 , 上一步可能是從j點過來 或者從i+1點過來,有兩個前一狀態,
即 d[i][j][0] = min(d[i+1][j][0] + (機器人從i+1 走到 i 點期間 其餘亮着的燈所消耗的功率) , d[i+1][j][1] + (從j點走到i點期間 其餘沒關的燈所消耗的功率)) .
同樣d[i][j][1] = min(d[i][j-1][0] + (從i點到j點消耗的功率), d[i][j-1][1] + (從j-1到j點消耗的功率))。


#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;

//l、r分別表示最左面和最右面燈所在的座標,st是開始的路燈,w[i]代表位於座標i的路燈的功率
int l, r, n, st, sum, w[1005], d[1005][1005][4];
void dp()
{
    for(int i = 1; i <= (r - l); i++)//以區間相距i爲主循環
    {
        for(int j = l; j <= (r-i); j++)
        {
            //這一部分求的是d[i][i+j][0]
            sum = d[j+1][j+i][2];
            //如果上一狀態已求出,那麼他所存的剩餘燈消耗的功率一定爲正數
            if(sum != -1)
            {
                d[j][i+j][2] = d[j+1][i+j][2] - w[j];//更新當前剩餘的燈的功率和

                //如果上一狀態是可行的、合法的而且已求出, 那麼他的狀態一定是>=0的
                if(d[j+1][j+i][0] >= 0 && d[j+1][j+i][1] >= 0)
                {
                    if(d[j+1][j+i][0] + sum < d[j+1][j+i][1] + i*sum)
                        d[j][i+j][0] = d[j+1][i+j][0] + sum;
                    else
                        d[j][i+j][0] = d[j+1][i+j][1] + i*sum;
                }
                //如果上兩狀態中只有一個是可行的,就只能由那個得來
                else if(d[j+1][j+i][0] >= 0 || d[j+1][j+i][1] >= 0)
                {
                    if(d[j+1][j+i][0] >= 0)
                        d[j][i+j][0] = d[j+1][i+j][0] + sum;
                    else
                        d[j][i+j][0] = d[j+1][i+j][1] + i*sum;
                }
            }
            //這一部分求的是d[j][j+i][1]
            sum = d[j][i+j-1][2];
            if(sum != -1)
            {
                d[j][i+j][2] = d[j][i+j-1][2] - w[i+j];
                if(d[j][i+j-1][0] >= 0 && d[j][i+j-1][1] >= 0)
                {
                    if(d[j][i+j-1][0] + i*sum < d[j][i+j-1][1] + sum)
                        d[j][i+j][1] = d[j][i+j-1][0] + i*sum;
                    else
                        d[j][i+j][1] = d[j][i+j-1][1] + sum;
                }
                else if(d[j][i+j-1][0] >= 0 || d[j][i+j-1][1] >= 0)
                {
                    if(d[j][j+i-1][0] >= 0)
                        d[j][i+j][1] = d[j][i+j-1][0] + i*sum;
                    else
                        d[j][i+j][1] = d[j][i+j-1][1] + sum;
                }
            }
        }
    }
}
int main()
{
    while(scanf("%d", &n) != EOF)
    {
        memset(w, 0, sizeof(w));
        memset(d, -1, sizeof(d));//先初始化所有狀態爲-1,一個不可能的值
        scanf("%d", &st);
        sum = 0;
        l = 10e5;
        r = 0;
        for(int i = 1; i <= n; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            w[a] = b;
            sum += b;//這裏sum存的是除去開始路燈,其他所有燈的功率和
            if(i == st)
            {
                sum -= b;
                st = a;
            }
            if(a < l)
                l = a;
            if(a > r)
                r = a;
        }
        //d[i][j][2] 存儲關閉i至j區間後 其他沒關的燈的功率和
        d[st][st][0] = d[st][st][1] = 0;
        d[st][st][2] = sum;
        dp();
        int ans = min(d[l][r][0], d[l][r][1]);
        printf("%d\n", ans);
    }
    return 0;
}
發佈了32 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章