题意:给定m个数字,有k种,求从中扔掉最少多少个,使得最后相同种类的数字都在一起。

题解:状态压缩DP,并不算太复杂,dp[i][j][mask]代表前i个珠子,以j结尾,且前面已经出现了mask珠子的最小代价。

View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int dp[105][6][40];
 6 const int inf=0x3f3f3f3f;
 7 int main()
 8 {
 9     int n,k;
10     while(scanf("%d%d",&n,&k),n||k)
11     {
12         memset(dp,0x3f,sizeof(dp));
13         dp[0][0][0]=0;
14         int ma=1<<k,ans;
15         for(int i=1;i<=n;i++)
16         {
17             int tp;
18             scanf("%d",&tp);
19             for(int j=0;j<ma;j++)
20             {
21                 for(int t=0;t<=k;t++)
22                 {
23                     if(dp[i-1][t][j]!=inf)
24                     {
25                         if(t==0)
26                         {
27                             dp[i][0][0]=dp[i-1][t][j]+1;
28                             dp[i][tp][(1<<(tp-1))]=dp[i-1][t][j];
29                         }
30                         else if(t!=tp)
31                         {
32                             dp[i][t][j]=min(dp[i][t][j],dp[i-1][t][j]+1);
33                             if(!(j&(1<<(tp-1))))
34                                 dp[i][tp][j|(1<<(tp-1))]=min(dp[i][tp][j|(1<<(tp-1))],dp[i-1][t][j]);
35                         }
36                         else
37                             dp[i][t][j]=min(dp[i][t][j],dp[i-1][t][j]);
38                     }
39 
40                 }
41             }
42         }
43         ans=inf;
44         for(int i=1;i<=k;i++)
45             for(int j=0;j<ma;j++)
46                 ans=min(ans,dp[n][i][j]);
47         printf("%d\n",ans);
48     }
49     return 0;
50 }