洛谷 4302 BZOJ 1090 SCOI2003 字符串折叠 UVA1630 Folding(输出方案版)

【题解】

  区间DP.  设f[i][j]表示i~j的最小代价。再枚举中间点k,很容易想到转移方程为f[i][j]=min(f[i][j],f[i][k]+f[k][j]),同时如果i~k可以通过重复获得i~j,那么f[i][j]=min(f[i][j],f[i][k]+len(x)+2),这里的len(x)是指重复次数在十进制下有多少位。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define LL long long
 5 #define rg register
 6 #define N 200
 7 using namespace std;
 8 int n,m,f[N][N];
 9 char s[N];
10 inline int read(){
11     int k=0,f=1; char c=getchar();
12     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
13     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
14     return k*f;
15 }
16 inline bool check(int l,int r,int end){
17     int l1=r-l+1,l2=end-l+1;
18     if(l2%l1) return 0;
19     m=l2/l1;
20     for(rg int i=1;i<=m;i++){
21         int st=l+(i-1)*l1;
22         for(rg int j=0;j<l1;j++) if(s[l+j]!=s[st+j]) return 0;
23     }
24     return 1;
25 }
26 inline int qlen(int x){
27     int cnt=0;
28     while(x){
29         x/=10;
30         cnt++;
31     }
32     return cnt;
33 }
34 int main(){
35     scanf("%s",s+1); n=strlen(s+1);
36     for(rg int i=0;i<=n;i++)
37         for(rg int j=i;j<=n;j++) f[i][j]=j-i+1;
38     for(rg int l=0;l<=n;l++){
39         for(rg int i=1;i+l-1<=n;i++){
40             int j=i+l-1;
41             for(rg int k=i;k<=j;k++){
42                 f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
43                 if(check(i,k,j)){
44                     f[i][j]=min(f[i][j],f[i][k]+2+qlen(m));
45 //                  printf("%d %d %d\n",i,k,j);
46                 }
47             }
48         }
49     }
50     printf("%d\n",f[1][n]);
51     return 0;
52 }
View Code

   输出方案的版本。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define LL long long
 5 #define rg register
 6 #define N 200
 7 using namespace std;
 8 int n,m,f[N][N],ans[N],from[N][N];
 9 char s[N];
10 inline int read(){
11     int k=0,f=1; char c=getchar();
12     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
13     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
14     return k*f;
15 }
16 inline bool check(int l,int r,int end){
17     int l1=r-l+1,l2=end-l+1;
18     if(l2%l1) return 0;
19     m=l2/l1;
20     for(rg int i=1;i<=m;i++){
21         int st=l+(i-1)*l1;
22         for(rg int j=0;j<l1;j++) if(s[l+j]!=s[st+j]) return 0;
23     }
24     return 1;
25 }
26 inline int qlen(int x){
27     int cnt=0;
28     while(x){
29         x/=10;
30         cnt++;
31     }
32     return cnt;
33 }
34 void out(int l,int r){
35     if(f[l][r]==r-l+1){
36         for(rg int i=l;i<=r;i++) printf("%c",s[i]);
37         return;
38     }
39     int k=from[l][r];
40     if(check(l,k,r)){
41         printf("%d(",m);
42         out(l,k);
43         printf(")");
44     }
45     else{
46         out(l,k); out(k+1,r);
47     }
48 }
49 int main(){
50     while(scanf("%s",s+1)!=EOF){
51         n=strlen(s+1);
52         for(rg int i=0;i<=n;i++)
53             for(rg int j=i;j<=n;j++) f[i][j]=j-i+1;
54         for(rg int l=0;l<=n;l++){
55             for(rg int i=1;i+l-1<=n;i++){
56                    int j=i+l-1;
57                 for(rg int k=i;k<=j;k++){
58                     if(f[i][k]+f[k+1][j]<f[i][j]){
59                         f[i][j]=f[i][k]+f[k+1][j];
60                         from[i][j]=k;
61                     }
62                     if(check(i,k,j)){
63                         int tmp=f[i][k]+2+qlen(m);
64                         if(tmp<f[i][j]){
65                             f[i][j]=tmp;
66                             from[i][j]=k;
67                         }
68 //                      printf("%d %d %d\n",i,k,j);
69                     }
70                 }
71             }
72         }
73         out(1,n);
74         puts("");
75     }
76 //    printf("%d\n",f[1][n]);
77     return 0;
78 }
View Code

 

posted @ 2018-08-11 23:46  Driver_Lao  阅读(138)  评论(0编辑  收藏  举报