P1220 关路灯(区间dp)

这题目想了很有一段时间,最后发现关一个区间的路灯最后的位置要么在最左端要么在最右端,只有两种状态所以建立状态,[i,j]表示这个区间的路灯最小消耗,0代表在最左端,1代表在最右端。这题目还有个坑点不能用while(scanf("%d%d",&n,&s)==2)一直90分最后看别人的把while去了就过了。。。汗颜。。。

状态方程式dp[j][i][0]=min(dp[j+1][i][0]+(x[j+1]-x[j])*(sum[n]-(sum[i]-sum[j])),dp[j+1][i][1]+(x[i]-x[j])*(sum[n]-(sum[i]-sum[j])))

      和dp[j][i][1]=min(dp[j][i-1][0]+(x[i]-x[j])*(sum[n]-(sum[i-1]-sum[j-1])),dp[j][i-1][1]+(x[i]-x[i-1])*(sum[n]-(sum[i-1]-sum[j-1])))

sum表示灯泡功率的前缀和每一个区间[j,i]只会由[j+1,i]和[j,i-1]推出,所以状态方程如上。

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn=1000;
const int inf=99999999;
int n,s;
int dp[maxn][maxn][2]={},x[maxn]={},w[maxn]={},sum[maxn]={};
inline int cime(int x,int y,int x1,int y1){
    return abs(dp[x][y][2]-dp[x1][y1][1]);
}
int main()
{
    scanf("%d%d",&n,&s);
        memset(dp,999,sizeof(dp));
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++){
            scanf("%d%d",&x[i],&w[i]);
            sum[i]=sum[i-1]+w[i];
        }
        dp[s][s][0]=dp[s][s][1]=0;
        for(int i=s;i<=n;i++)
        for(int j=i-1;j>=1;j--){
            dp[j][i][0]=min(dp[j+1][i][0]+(x[j+1]-x[j])*(sum[n]-(sum[i]-sum[j])),dp[j+1][i][1]+(x[i]-x[j])*(sum[n]-(sum[i]-sum[j])));
            dp[j][i][1]=min(dp[j][i-1][0]+(x[i]-x[j])*(sum[n]-(sum[i-1]-sum[j-1])),dp[j][i-1][1]+(x[i]-x[i-1])*(sum[n]-(sum[i-1]-sum[j-1])));
        }
        printf("%d\n",min(dp[1][n][1],dp[1][n][0]));

    return 0;
}


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