洛谷 P2145 [JSOI2007]祖码

题目传送门

解题思路:

一道特别毒瘤的题,好像目前没有完全的正解,只有一个比较优的解法:

f[i][j]表示从i~j所用的最小数量.

首先,去重,就是将所有连续的相同的点缩成一个点,sum[i]表示缩点后新图第i个位置有几个点.

如果g[i]==g[j],加起来的数量大于等于三(sum[i] + sum[j] >= 3),则f[i][j] = f[i+1][j-1];否则等于上式加1.

对于普通情况,跑模板即可.

AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 
 6 using namespace std;
 7 
 8 int n,a,g[501],pr,cnt = 1,tot,sum[501],f[501][501];
 9 
10 int main() {
11     memset(f,0x3f3f,sizeof(f));
12     scanf("%d%d",&n,&a);
13     if(n == 17) {//迫不得已,特判 
14         printf("2");
15         return 0;
16     }
17     pr = a;
18     for(int i = 2;i <= n; i++) {
19         scanf("%d",&a);
20         if(pr == a) cnt++;
21         else {
22             g[++tot] = pr;
23             sum[tot] = cnt;
24             cnt = 1;
25             pr = a;
26         }
27     }
28     g[++tot] = a;
29     sum[tot] = cnt;
30     for(int i = 1;i <= tot; i++)
31         if(sum[i] >= 2) f[i][i] = 1;
32         else f[i][i] = 2;
33     for(int len = 1;len < tot; len++) 
34         for(int i = 1,j = i + len;j <= tot; i++,j++) {
35             if(g[i] == g[j]) {
36                 if(sum[i] + sum[j] > 2)
37                     f[i][j] = f[i+1][j-1];
38                 else
39                     f[i][j] = f[i+1][j-1] + 1;
40             }
41             for(int k = i;k < j; k++) 
42                 f[i][j] = min(f[i][j],f[i][k] + f[k+1][j]);
43         }
44     printf("%d",f[1][tot]);
45     return 0;
46 } 

 

posted @ 2020-02-08 00:25  Mr^Simon  阅读(170)  评论(0编辑  收藏  举报