Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 1887 | Accepted: 882 |
Description
You are given a row of m stones each of which has one of k different colors. What is the minimum number of stones you must remove so that no two stones of one color are separated by a stone of a different color?
Input
The input test file will contain multiple test cases. Each input test case begins with a single line containing the integers m and k where 1 ≤m ≤ 100 and 1 ≤ k ≤ 5. The next line contains m integersx1, …, xm each of which takes on values from the set {1, …,k}, representing the k different stone colors. The end-of-file is marked by a test case withm = k = 0 and should not be processed.
Output
For each input case, the program should the minimum number of stones removed to satisfy the condition given in the problem.
Sample Input
10 3 2 1 2 2 1 1 3 1 3 3 0 0
Sample Output
2
Hint
In the above example, an optimal solution is achieved by removing the 2nd stone and the 7th stone, leaving three “2” stones, three “1” stones, and two “3” stones. Other solutions may be possible.
Source
题目大意:
给出一个长度为N有K种颜色的石子的序列,求最小去除石子个数,使得全部颜色相同的石子在一起。
解题思路:
正向思考的话,后效性非常强,删除石子的状态转移非常复杂。那么我们可以考虑逆向思考。我们用这些石子构造一个最长的所有颜色相同的石子在一起的序列。则这样的后效性就小了特别多,状态转移也就非常好写了。
用dp[i][j][k]表示用前i个石头,最后一个为j,已经使用的石头的颜色的状态为k时,组成的最长序列。那么我们初始化另每一个石子创立一个只有它自己的序列。然后在枚举状态更新dp数组的时候对每个序列的各个情况不断更新。最后用N减去最长的序列即为所求。(具体状态转移见代码)。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn=100+3;
const int maxk=5+1;
int color[maxn],N,K,dp[maxn][maxk][1<<maxk];//dp[i][j][k]表示用前i个石头,最后一个为j,已经使用的石头的颜色的状态为k时,组成的最长序列
int main()
{
while(~scanf("%d%d",&N,&K)&&(N||K))
{
for(int i=0;i<N;++i)//初始化
for(int j=0;j<K;++j)
for(int k=0;k<(1<<K);++k)
dp[i][j][k]=0;
for(int i=0;i<N;++i)
{
scanf("%d",&color[i]);
--color[i];//颜色改为从1开始
dp[i][color[i]][1<<color[i]]=1;
}
for(int i=0;i<N-1;++i)//使用刷表法更新dp数组
for(int j=0;j<K;++j)
for(int k=0;k<(1<<K);++k)
if(dp[i][j][k])//这个序列不为空,才进行添加
{
if(color[i+1]==j)//新加入的石子和最后一个相同,就直接加入
dp[i+1][j][k]=max(dp[i+1][j][k],dp[i][j][k]+1);
else if((1<<color[i+1])&k)//和最后一个颜色不同并且这个颜色以前出现过,则不加入
dp[i+1][j][k]=max(dp[i+1][j][k],dp[i][j][k]);
else
{
dp[i+1][j][k]=max(dp[i+1][j][k],dp[i][j][k]);//不加入
dp[i+1][color[i+1]][k|(1<<color[i+1])]=max(dp[i+1][color[i+1]][k|(1<<color[i+1])],dp[i][j][k]+1);//加入新颜色的石子
}
}
int ans=INF;
for(int j=0;j<K;++j)
for(int k=0;k<(1<<K);++k)
ans=min(ans,N-dp[N-1][j][k]);
printf("%d\n",ans);
}
return 0;
}