POJ 2430(状态设计类)

本题的二维状态是比较好想的吧,

直接定义d[ i ][ j ] 为当前位置为i还有j个栅栏可用时的最小代价。

首先按位置排序。

状态转移时需要从当前出发 

若  k>=1 d[ i ][ j ]可以开一个宽为1栅栏 最多将从i开始到最后一个和 i在一排j放到一个栅栏中,或者开一个宽度为2的栅栏,可延伸到最后

若  k>=2 d[ i ][ j ]可同时 开两个栅栏。

但该算法时间达到o(N^3)时间复杂度太高,且状态转移不太适合优化。

于是在加一维。

1 表示当前位置前面有一个宽为1且在第一排的栅栏还未封口。

2 表示当前位置前面有一个宽为1且在第二排的栅栏还未封口。

3 有以上两个

4 表示当前位置前面有一个宽为1栅栏还未封口。

这样状态便可以转移,而且时间复杂度为o(N^2)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,n) for(int (i)=0;(i)<(n);i++)
#define Rep(i,n) for(int (i)=1;(i)<=(n);i++)
const int maxn = 1111;
const int inf = 1e9;
struct node{
  int ty,p;
  bool operator<(const node& rhs)const{
    if(p!=rhs.p) return p<rhs.p;
    else return ty<rhs.ty;
  }
}a[maxn];
int pre[maxn],n;
int dist(int i,int j){
  return a[j].p-a[i].p;
}
int K,b,d[maxn][5][maxn];
void init(){
  for(int i=1;i<=n+1;i++)
     for(int k=0;k<5;k++)
       for(int j=0;j<=K;j++)
           d[i][k][j] = -1;
  a[0].p = a[1].p-1;
  int p[3]={0};
  for(int i=1;i<=n;i++){
     pre[i] = p[a[i].ty];
     p[a[i].ty] = i;
  }
}
int dp(int i,int j,int k){
  if(d[i][j][k]!=-1) return d[i][j][k];
  int& ans = d[i][j][k];
  if(i==n+1){
     if(k) ans = inf;
     else ans = 0;
     return ans;
  }
  ans = inf;
  if(j==3||j==1||j==2){
     if(a[i].ty==j||j==3)
        ans = min(ans,dp(i+1,j,k)+dist(pre[i],i));
  }
  if(j==1||j==2){
      if(a[i].ty!=j&&k>=1)
        ans = min(ans,dp(i+1,3,k-1)+1);
  }
  if(j==4){
      ans = min(ans,dp(i+1,4,k)+2*dist(i-1,i));
  }
  if(k>=1)
     ans = min(ans,dp(i+1,a[i].ty,k-1)+1);
  if(k>=1)
     ans = min(ans,dp(i+1,4,k-1)+2);
  return ans;
}
int main()
{
    while(scanf("%d %d %d",&n,&K,&b)==3){
       Rep(i,n) scanf("%d %d",&a[i].ty,&a[i].p);
       sort(a+1,a+1+n);
       init();
       printf("%d\n",min(dp(2,a[1].ty,K-1)+1,dp(2,4,K-1)+2));
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值