码迷,mamicode.com
首页 > 其他好文 > 详细

CSU 1620: A Cure for the Common Code (区间DP KMP预处理)

时间:2015-05-18 01:09:54      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:

链接 : http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1620


题意 : 给一个字符串 问怎么压缩字符串使得最终个数最小 具体怎么压缩请参照图示 很好明白。


题目就是需要找到 对于每个后缀 看成一个新字符串 找出它的前缀的最小循环节。

过程和大白书 P213页 是一样的,只需要对每个后缀跑一遍KMP求出周期。

剩下的过程就是区间DP了。

dp[i][j] = min ( dp[i][k], dp[k+1][j] );

如果i - j这一段存在循环节,那么dp[i][j]还可以使用压缩规则进行再一次的更新。最终dp[1][n]就是答案。


#pragma comment(linker, "/STACK:10240000,10240000")
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#define mod 4294967296
#define MAX 0x3f3f3f3f
#define lson o<<1, l, m
#define rson o<<1|1, m+1, r
#define SZ(x) ((int)ans.size())
#define MAKE make_pair
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define mem(a) memset(a, 0, sizeof(a))
const double pi = acos(-1.0);
const double eps = 1e-9;
const int N = 503;
const int M = 20005;
typedef long long ll;
using namespace std;

int f[N], g[N][N], dp[N][N], v[N][N];
char s[N];

void KMP(char *s, int r) {
    f[0] = f[1] = 0;
    for(int i = 1; s[i]; i++) {
        int j = f[i];
        while(j && s[j] != s[i]) j = f[j];
        f[i+1] = (s[i] == s[j] ? j + 1 : 0);
    }
    int n = strlen(s);
    for(int i = 2; i <= n; i++) {
        if(f[i] > 0 && i % (i-f[i]) == 0) {
            g[r+1][i+r] = i/(i-f[i]);
        }
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    int ca = 1;
    while(scanf("%s", s) && s[0] != '0') {
        int n = strlen(s);
        memset(g, -1, sizeof(g));
        for(int i = 0; i < n; i++) {
            KMP(s+i, i);
        }
        printf("Case %d: ", ca++);
        for(int i = 1; i <= n; i++) {
            for(int j = i; j <= n; j++) {
                //printf("--g[%d][%d] = %3d\n", i, j, g[i][j]);
                if(g[i][j] == -1) {
                    v[i][j] = j-i+1;
                } else {
                    int num = g[i][j];
                    int cnt = (j-i+1) / g[i][j];
                    while(num) {
                        num /= 10;
                        cnt++;
                    }
                    if(g[i][j] != j-i+1) cnt += 2;
                    v[i][j] = min(j-i+1, cnt);
                }
                //printf("++g[%d][%d] = %3d, \n", i, j, v[i][j]);

            }
        }

        for(int len = 1; len <= n; len++) {
            for(int i = 1; i <= n-len+1; i++) {
                int j = i + len - 1;
                dp[i][j] = v[i][j];
                for(int k = i; k < j; k++) {
                    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j]);
                }
                if(g[i][j] != -1) {
                    int num = (j-i+1) / g[i][j], tmp = 0;
                    int p = i+num-1;
                    if(num != 1) tmp += 2;
                    int y = g[i][j];
                    while(y) {
                        y /= 10;
                        tmp++;
                    }
                    dp[i][j] = min(dp[i][j], tmp + dp[i][p]);
                }
            }
        }
        printf("%d\n", dp[1][n]);

    }

	return 0;
}



CSU 1620: A Cure for the Common Code (区间DP KMP预处理)

标签:

原文地址:http://blog.csdn.net/u013923947/article/details/45803771

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!