UVa1630 Folding/poj 2176 Folding/zoj 1554 Folding

        题意:给一个由大写字母组成的串,需要压缩成尽可能短的串,可以嵌套压缩。例如:

AAAAAAAAAABABABCCD -> 9(A)3(AB)CCD

NEERCYESYESYESNEERCYESYESYES -> 2(NEERC3(YES))

        思路:DP[i][j]。i,j分别表示起始位置,终止位置,数组存该段压缩后的长度。一个串的最短压缩可以有两种情况:1.其本身是重复的,压缩其本身达到最短。2.将其分为两段,两段压缩后连接达到最短。

        这题坑了我很长时间。。。但是还是要感谢这道题,逼我学会了生成随机数据,文件比较。因为一直WA,我生成了1000行随机串,和别人的程序比较。然后不得不说的是UVa的数据比较强,在其他OJ上过的程序在UVa上WA,最后终于还是AC了。


#include <iostream>  
#include <stdio.h>  
#include <cmath>  
#include <algorithm>  
#include <iomanip>  
#include <cstdlib>  
#include <string>  
#include <memory.h>  
#include <vector>  
#include <queue>  
#include <stack>  
#include <ctype.h>  
#define INF 1000000

using namespace std;

string str;
int DP[110][110];
string fold[110][110];

int judge(int l,int r){//判断是否为重复串 
	for(int i=1;i<=(r-l+1)/2;i++){
		if((r-l+1)%i)continue;
		bool flag=true;
		for(int j=l;j+i<=r;j++){
			if(str[j]!=str[j+i]){
				flag=false;
				break;
			}
		}
		if(flag)return i;
	}
	return false;
}

int fun(int l,int r){
	if(DP[l][r]!=-1)return DP[l][r];
	if(l==r){
		DP[l][r]=1;
		fold[l][r]=str[l];
		return 1;
	}
	int re=INF;
	//区间合并 
	int k;
	for(int i=l;i<r;i++){
		int tmp=fun(l,i)+fun(i+1,r);
		if(tmp<re){
			k=i;re=tmp;
		}
	}
	fold[l][r]=fold[l][k]+fold[k+1][r];
	re=fun(l,k)+fun(k+1,r);
	//重复串压缩 
	int len=judge(l,r);
	if(len){
		bool test=true;
		for(int i=l;i<=r;i++){//不要把括号作为压缩对象 
			if(str[i]=='('||str[i]==')')test=false;
		}
		char t[10];
    	sprintf(t,"%d",(r-l+1)/len);
    	string newstr=t+string("(")+fold[l][l+len-1]+string(")");
		if(test&&newstr.size()<re){
			re=newstr.size();
			fold[l][r]=newstr;
		}
	}
	//
	DP[l][r]=re;
	return re;
}

int main(){
	while(cin>>str){
		int R=str.size()-1;
		memset(DP,-1,sizeof(DP));
		fun(0,R);
		cout<<fold[0][R]<<endl;
	}
	return 0;
}


你可能感兴趣的:(dp,uva)