CF1114D Flood Fill

题目链接

题目大意

一排有n个方格,已知初始的颜色,现在按一定规则改变它们的颜色。
开始操作前,先选定一个方格x;再重复操作:将包含该方格的同色区域(一些连续的同色方格)全部改为一种颜色,直到所有方格同色。
如何选择方格可以使得操作重复次数最少?输出这个最小值。

思路

先把颜色相同的方格看成一个,生成一个新的数组bf[],bf[]有cnt个元素。

  • 选任意一个方格,cnt-1次操作一定可以完成;
  • 对于某个方格,若其两边有一对颜色相同个方格,就可以少一次操作,将这一对方格及其中间的方格看作一个,再往两边找,若还有方格,就又可以减少一次操作……(搜索的暴力方法就基本完善了)
  • 把相同的颜色连上线,则对于每一个方格,横跨它的、不相交的连线有多少条,就可以减少多少次操作。(如图,对于6,就有两条的,红色和紫色)

动态规划的雏形大概就是:f[i][k]表示从第i个方格开始的k个方格中,最多可连线条数,那么

 

 

然而,TLE。考虑pre[i][k]表示  从i开始的、长度小于等于k的所有区间中的最大连线数,fore[i][k]表示  以i结束的、长度小于等于k的所有区间中的最大连线数。

似乎解决了,然而又MLE。注意到只需保留pre[][k-2],pre[][k-1],pre[][k],fore[][k-2],fore[][k-1],fore[][k]所以还要用滚动数组。

 

最终的代码就是这样了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=5001;
 4 int n,f[N][N],bf[N],cnt,ans,pre[N][3],fore[N][3];
 5 
 6 int main()
 7 {
 8 //    freopen("in.in","r",stdin);
 9 //    freopen("2.out","w",stdout);
10     scanf("%d",&n);
11     cnt++;
12     scanf("%d",&bf[cnt]);
13     for(int i=2;i<=n;i++)
14     {
15         int tem;
16         scanf("%d",&tem);
17         if(tem!=bf[cnt])
18         {
19             cnt++;
20             bf[cnt]=tem;
21         }
22     }
23     
24     for(int k=3;k<=cnt;k++)
25     {
26         for(int i=1;i<=cnt-k+1;i++)
27         {
28             f[i][k]=max(fore[i+k-2][(k-2)%3],max(pre[i+1][(k-2)%3],f[i][k]));
29             if(bf[i]==bf[i+k-1])f[i][k]++;
30             pre[i][k%3]=max(pre[i][(k-1)%3],f[i][k]);
31             fore[i+k-1][k%3]=max(fore[i+k-1][(k-1)%3],f[i][k]);
32         }
33     }
34     int ans=max(pre[1][cnt%3],fore[cnt][cnt%3]);
35     ans=cnt-1-ans;
36     printf("%d\n",ans);
37     return 0;
38 }

 

 

 

posted @ 2019-02-14 12:27  liqgnonqfu  阅读(187)  评论(0编辑  收藏  举报