Description
Ciocio在执行刺杀计划的过程中被警方抓捕,被送到了一座监狱。与Ciocio同时入狱的共有N-1位罪犯(即共有N个人)。这些罪犯有的是白人,有的是黑人。狱警要给他们分房间。但是,监狱为减少不必要的冲突,要求:要么保证整个房间都是同一肤色的罪犯,或者同一房间两种不同肤色罪犯的人数差不超过M。另外,现在N个罪犯被锁链拴成成一排,狱警只会把连续一段的罪犯分进一个房间。狱警想知道,至少需要多少个房间(假设每个房间可容纳无限罪犯)。
Input
第一行包括N和M。
之后N行,每行一个整数,代表罪犯的肤色,1表示白色,2表示黑色。
Output
一个整数,表示最小需要房间的数量。
Sample Input
12 1
1
1
1
1
2
1
2
1
1
2
2
2
Sample Output
2
Hint
对于30%的数据,有1 ≤ N ,M≤ 50;
对于60%的数据,有1 ≤ N ,M≤ 1000;
对于100%的数据,有1 ≤ N,M ≤ 2500。
【分析】
很明显是DP,为什么很明显呢?因为题目要求的是连续的一段要放在一起。我们这样定义状态:F[i]表示以i结尾的人,最少用多少个房间。然后用两个数组w,b分别来记录白人和黑人的前缀和。
方程:F[i]=min(F[k])+1; abs((w[i]-w[k])-(b[i]-b[k]))<=M||w[i]-w[k]==0||b[i]-b[k]==0;
【代码】
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=999999999;
int N,M;
int v[2505],w[2505],b[2505],f[2505];
void _init()
{
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++)
{
f[i]=INF;
scanf("%d",&v[i]);
}
}
void _solve()
{
for(int i=1;i<=N;i++)
{
w[i]=w[i-1];
b[i]=b[i-1];
if(v[i]==1)
w[i]++;
else
b[i]++;
}
f[0]=0;
for(int i=1;i<=N;i++)
{
int temp=INF;
for(int k=0;k<=i;k++)
if(abs(w[i]-w[k]-b[i]+b[k])<=M||w[i]-w[k]==0||b[i]-b[k]==0)
temp=min(temp,f[k]);
f[i]=temp+1;
}
printf("%d\n",f[N]);
}
int main()
{
_init();
_solve();
return 0;
}