本题的二维状态是比较好想的吧,
直接定义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;
}