UVALive - 3363 String Compression 区间DP

题目大意:有一串字符串,现在有一种转换规则,如果字符串中出现循环的子串,可以将其转化为 :子串数量(子串)

现在问这个字符串的最短长度

解题思路:区间dp,然后分类讨论,这题的难点是如何再进行缩减

将情况分为两种

一种是区间刚好符合缩减情况的,找出该区间的循环节,看能否继续缩减即可

另一种情况就是普通的区间DP了

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 210
#define INF 0x3f3f3f3f
char str[maxn];
int dp[maxn][maxn];
int vis[maxn][maxn];
int d;

int solve(int s, int e) {
    int len = (e - s + 1) / 2;
    bool mark = true;
    int ans, i;
    for(i = 1; i <= len; i++)
        if((e - s + 1) % i == 0) {
            mark = false;
            for(int j = 0; j < i; j++) {
                char t = str[s + j];
                for(int k = s + j; k <= e; k += i)
                    if(str[k] != t) {
                        mark = true;
                        break;
                    }
                if(mark)
                    break;
            }
            if(!mark) {
                ans  = i;
                d = i;
                break;
            }
        }

    if(!mark) {
        int length;
        if( (e - s + 1) / ans >= 100)
            length = 3;
        else if( (e - s + 1) / ans >= 10)
            length = 2;
        else
            length = 1;

        if(length + 2 + i <= (e - s + 1))
            return length + 2 + i;
        else
            return (e - s + 1);
    }
    else
        return (e - s + 1);
}

int main() {
    int test;
    scanf("%d", &test);
    while(test--) {
        scanf("%s", str + 1);
        int len = strlen(str + 1);
        memset(vis, 0, sizeof(vis));
        for(int i = 1; i <= len; i++)
            dp[i][i] = 1;
        for(int i = 1; i < len; i++)
            for(int j = 1; j + i <= len; j++) {
                int e = j + i;
                dp[j][e] = solve(j,e);
                if(dp[j][e] == (e - j + 1))
                    for(int k = j; k < e; k++)
                        dp[j][e] = min(dp[k + 1][e] + dp[j][k], dp[j][e]);
                else {
                    vis[j][e] = 1;
                    int t = dp[j][e], Min = dp[j][e];
                    for(int duan = 3; duan < d; duan++)
                        for(int start = j; start + duan < j + d; start++) {
                            if(vis[start][start + duan]) {
                                Min = min(Min, t - (duan + 1) + dp[start][start + duan]);
                            }
                        }
                    dp[j][e] = Min;
                }
            }
        printf("%d\n", dp[1][len]);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-02 06:59:51

UVALive - 3363 String Compression 区间DP的相关文章

UVALive 3363 String Compression

题解: 区间dp 注意这题有两种状态. 1. dp[i][j] = min( dp[i][j], dp[i][k] + dp[k+1][j] ); 将区间拆分,有两个小的转化而来 2. dp[i][j] = min(dp[i][j], dp[i][ i +k - 1] + 2 + num.length );整体上看,整体上可以化简.由一个小的转化而来 trick:第二个是dp[i][ i +k - 1]而不是k,因为一个小的也可以是重复的 代码: #include<bits/stdc++.h>

NYOJ 1067 Compress String(区间dp)

Compress String 时间限制:2000 ms  |  内存限制:65535 KB 难度:3 描述 One day,a beautiful girl ask LYH to help her complete a complicated task-using a new compression method similar to Run Length Encoding(RLE) compress a string.Though the task is difficult, LYH is

Educational Codeforces Round 25 F. String Compression(kmp+dp)

题目链接:Educational Codeforces Round 25 F. String Compression 题意: 给你一个字符串,让你压缩,问压缩后最小的长度是多少. 压缩的形式为x(...)x(...)  x表示(...)这个出现的次数. 题解: 考虑dp[i]表示前i个字符压缩后的最小长度. 转移方程解释看代码,这里要用到kmp来找最小的循环节. 当然还有一种找循环节的方式就是预处理lcp,然后通过枚举循环节的方式. 这里我用的kmp找的循环节.复杂度严格n2. 1 #inclu

UVALive 3516 Exploring Pyramids 区间dp+计数原理

题目链接:点击打开链接 给定多叉树的先序遍历结果,求多叉树的同构数 思路:区间dp import java.io.PrintWriter; import java.util.ArrayList; import java.util.Scanner; public class Main { int min(int a,int b){return a>b?b:a;} int max(int a,int b){return a>b?a:b;} long min(long a,long b){retur

UVALive 4987---Evacuation Plan(区间DP)

题目链接 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2988 problem Description Flatland government is building a new highway that will be used to transport weapons from its main weapon plan

uva live 4394 String painter 区间dp

// uva live 4394 String painter // // 这一题是训练指南上dp专题的习题,初看之下认为仅仅是稍微复杂了一点 // 就敲阿敲阿敲,两个半小时后,发现例子过了.然而自己给出的数据跪了 // 交了也wa了,才发现,自己的方法是有问题的,假设是将两个串同一时候考虑 // 的话,比方: dp[i][j] 表示从i到j,s串刷成目标b串所须要的最小的花费 // 然后依据区间的端点的字符特点,进行状态转移,然而可能是我太搓了, // 发现这种状态转移是不正确的.比方edc和

hdu 2476 String painter(区间dp)

String painter                                                                                                Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)                                                         

UVALive 3516 Exploring Pyramids (区间dp)

#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; #define ll long long const int maxn = 310; const ll mod = 1e9; char s[maxn]; ll dp[maxn][maxn]; ll solve(int i, int j) { if(i == j) retu

区间DP UVA 1351 String Compression

题目传送门 1 /* 2 题意:给一个字符串,连续相同的段落可以合并,gogogo->3(go),问最小表示的长度 3 区间DP:dp[i][j]表示[i,j]的区间最小表示长度,那么dp[i][j] = min (dp[j][k] + dp[k+1][i+j-1]), 4 digit (i / k) + dp[j][j+k-1] + 2)后者表示可以压缩成k长度连续相同的字符串 4.5 详细解释 5 */ 6 /*****************************************