NOJ 1111 保险箱的密码 【大红】 [区间dp]

传送门

保险箱的密码 【大红】

时间限制(普通/Java) : 1000 MS/ 3000 MS          运行内存限制 : 65536 KByte
总提交 : 118            测试通过 : 3 

题目描述

最近sed同学设计了一套保险箱密码锁,密码锁上有依次排好的0、1数字键,保险箱密码是由0和1组成的数字串。开启这个保险箱需要正确的密码,还需要将密码锁上数字键设定为对应的0或1,而这个过程需要特定的技巧:每次变换的工作:将密码锁上连续的0、1数字串用同样数目的全0或全1数字串代替。现给你正确的密码 (不超过200),请计算开启这个保险箱,最少需要经过多少次变换。

输入

 

第一行是一个正整数:测试用例数目,最多为100。之后,每个测试用例包括两行:

l       第1行给出密码锁上初始的0、1数字串(不超过200)

l       第2行给出保险箱的正确密码

 

输出

 

对于每个测试用例:

l       开启保险箱需要的最少变换数

 

样例输入

2
000
111
1011
0010

样例输出

1
2

 

题目来源

“IBM南邮杯”团队赛2009

 

Accepted
953MS
  724K
2732Byte
2015-02-10 10:20:01.0
Time Limit Exceed at Test 1
   
2724Byte
2015-02-10 10:18:11.0

 

题解:

区间dp

对于 i-j的区间,整个区间置0或置1,至多只会出现一次
因为你如果再置,就会把前面的操作覆盖,没有意义
所以,下面的操作长度,必然都小于 i-j

同时可以证明,重叠的区间操作也是没有意义的,同理:会覆盖前面的某些操作
所以,可以不断把区间缩小

加上记忆化就可以水过了,不过应该还有更加优化的方法,有待思考。

 

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cstdio>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<map>
  9 #include<set>
 10 #include<stack>
 11 #include<string>
 12 
 13 #define N 205
 14 #define M 105
 15 #define mod 10000007
 16 //#define p 10000007
 17 #define mod2 1000000000
 18 #define ll long long
 19 #define LL long long
 20 #define eps 1e-6
 21 #define inf 100000000
 22 #define maxi(a,b) (a)>(b)? (a) : (b)
 23 #define mini(a,b) (a)<(b)? (a) : (b)
 24 
 25 using namespace std;
 26 
 27 int T;
 28 char s[N];
 29 char t[N];
 30 int dp[N][N];
 31 int dp1[N][N];
 32 int dp0[N][N];
 33 int le;
 34 int ans;
 35 
 36 int fun(int l,int r);
 37 int fun0(int l,int r);
 38 int fun1(int l,int r);
 39 
 40 void ini()
 41 {
 42     memset(dp,-1,sizeof(dp));
 43     memset(dp1,-1,sizeof(dp1));
 44     memset(dp0,-1,sizeof(dp0));
 45     scanf("%s",s+1);
 46     scanf("%s",t+1);
 47     le=strlen(s+1);
 48 }
 49 
 50 int fun1(int l,int r)
 51 {
 52     if(dp1[l][r]!=-1) return dp1[l][r];
 53     int re;
 54     int st=l;
 55     int en=r;
 56     for(st=l;st<=r;st++){
 57         if(t[st]=='0') break;
 58     }
 59     if(st>r) return dp1[l][r]=0;
 60     for(en=r;en>=st;en--){
 61         if(t[en]=='0') break;
 62     }
 63     if(st==en){
 64         return dp1[l][r]=1;
 65     }
 66     re=fun0(st,en)+1;
 67     dp1[l][r]=re;
 68     return re;
 69 }
 70 
 71 int fun0(int l,int r)
 72 {
 73     if(dp0[l][r]!=-1) return dp0[l][r];
 74     int st=l;
 75     int en=r;
 76     int re;
 77     for(st=l;st<=r;st++){
 78         if(t[st]=='1') break;
 79     }
 80     if(st>r) return dp0[l][r]=0;
 81     for(en=r;en>=st;en--){
 82         if(t[en]=='1') break;
 83     }
 84     if(st==en){
 85         return dp0[l][r]=1;
 86     }
 87     re=fun1(st,en)+1;
 88     dp0[l][r]=re;
 89     return re;
 90 }
 91 
 92 int fun(int l,int r)
 93 {
 94     if(dp[l][r]!=-1) return dp[l][r];
 95     int st=l;
 96     int en=r;
 97     for(st=l;st<=r;st++){
 98         if(s[st]!=t[st]) break;
 99     }
100     if(st>r) return dp[l][r]=0;
101     for(en=r;en>=st;en--){
102         if(s[en]!=t[en]) break;
103     }
104     if(st==en){
105         return dp[l][r]=1;
106     }
107     int i;
108     int re=1000000000;
109     for(i=st+1;i<=en;i++){
110         re=min(re,fun(st,i-1)+fun(i,en));
111     }
112     re=min(re,fun1(st,en)+1);
113     re=min(re,fun0(st,en)+1);
114     dp[l][r]=re;
115     return re;
116 }
117 
118 void solve()
119 {
120     ans=fun(1,le);
121 }
122 
123 void out()
124 {
125     /*
126     int i,j;
127     for(i=1;i<=le;i++){
128         for(j=i;j<=le;j++){
129             printf(" i=%d j=%d dp1=%d dp0=%d dp=%d\n",i,j,dp1[i][j],dp0[i][j],dp[i][j]);
130         }
131     }*/
132     printf("%d\n",ans);
133 }
134 
135 int main()
136 {
137     //freopen("data.in","r",stdin);
138     //freopen("data.out","w",stdout);
139     scanf("%d",&T);
140     //for(int ccnt=1;ccnt<=T;ccnt++)
141     while(T--)
142     //scanf("%d%d",&n,&m);
143     //while(scanf("%s",s)!=EOF)
144     {
145         ini();
146         solve();
147         out();
148     }
149     return 0;
150 }

 

继续思考,将区间分成两部分时,原串和正确串已经相同的部分可以跳过,故可以减少好多操作,当成剪枝1

 

Accepted
375MS
  724K
2924Byte
2015-02-10 10:48:12.0
Wrong Answer at Test 1
   
2738Byte
2015-02-10 10:33:44.0
Accepted
953MS
  724K
2732Byte
2015-02-10 10:20:01.0
Time Limit Exceed at Test 1
   
2724Byte
2015-02-10 10:18:11.0

 

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cstdio>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<map>
  9 #include<set>
 10 #include<stack>
 11 #include<string>
 12 
 13 #define N 205
 14 #define M 105
 15 #define mod 10000007
 16 //#define p 10000007
 17 #define mod2 1000000000
 18 #define ll long long
 19 #define LL long long
 20 #define eps 1e-6
 21 #define inf 100000000
 22 #define maxi(a,b) (a)>(b)? (a) : (b)
 23 #define mini(a,b) (a)<(b)? (a) : (b)
 24 
 25 using namespace std;
 26 
 27 int T;
 28 char s[N];
 29 char t[N];
 30 int dp[N][N];
 31 int dp1[N][N];
 32 int dp0[N][N];
 33 int le;
 34 int ans;
 35 
 36 int fun(int l,int r);
 37 int fun0(int l,int r);
 38 int fun1(int l,int r);
 39 
 40 void ini()
 41 {
 42     memset(dp,-1,sizeof(dp));
 43     memset(dp1,-1,sizeof(dp1));
 44     memset(dp0,-1,sizeof(dp0));
 45     scanf("%s",s+1);
 46     scanf("%s",t+1);
 47     le=strlen(s+1);
 48 }
 49 
 50 int fun1(int l,int r)
 51 {
 52     if(dp1[l][r]!=-1) return dp1[l][r];
 53     int re;
 54     int st=l;
 55     int en=r;
 56     for(st=l;st<=r;st++){
 57         if(t[st]=='0') break;
 58     }
 59     if(st>r) return dp1[l][r]=0;
 60     for(en=r;en>=st;en--){
 61         if(t[en]=='0') break;
 62     }
 63     if(st==en){
 64         return dp1[l][r]=1;
 65     }
 66     re=fun0(st,en)+1;
 67     dp1[l][r]=re;
 68     return re;
 69 }
 70 
 71 int fun0(int l,int r)
 72 {
 73     if(dp0[l][r]!=-1) return dp0[l][r];
 74     int st=l;
 75     int en=r;
 76     int re;
 77     for(st=l;st<=r;st++){
 78         if(t[st]=='1') break;
 79     }
 80     if(st>r) return dp0[l][r]=0;
 81     for(en=r;en>=st;en--){
 82         if(t[en]=='1') break;
 83     }
 84     if(st==en){
 85         return dp0[l][r]=1;
 86     }
 87     re=fun1(st,en)+1;
 88     dp0[l][r]=re;
 89     return re;
 90 }
 91 
 92 int fun(int l,int r)
 93 {
 94     if(dp[l][r]!=-1) return dp[l][r];
 95     int st=l;
 96     int en=r;
 97     for(st=l;st<=r;st++){
 98         if(s[st]!=t[st]) break;
 99     }
100     if(st>r) return dp[l][r]=0;
101     for(en=r;en>=st;en--){
102         if(s[en]!=t[en]) break;
103     }
104     if(st==en){
105         return dp[l][r]=1;
106     }
107     int re=1000000000;
108     int en1,st2;
109     for(en1=st;en1<=en-1;en1++){
110         if(s[en1]==t[en1]) continue;
111         for(st2=en1+1;st2<=en;st2++){
112             if(s[st2]==t[st2]) continue;
113             re=min(re,fun(st,en1)+fun(st2,en));
114             en1=st2-1;
115             break;
116         }
117     }
118     re=min(re,fun1(st,en)+1);
119     re=min(re,fun0(st,en)+1);
120     dp[l][r]=re;
121     return re;
122 }
123 
124 void solve()
125 {
126     ans=fun(1,le);
127 }
128 
129 void out()
130 {
131     /*
132     int i,j;
133     for(i=1;i<=le;i++){
134         for(j=i;j<=le;j++){
135             printf(" i=%d j=%d dp1=%d dp0=%d dp=%d\n",i,j,dp1[i][j],dp0[i][j],dp[i][j]);
136         }
137     }*/
138     printf("%d\n",ans);
139 }
140 
141 int main()
142 {
143     //freopen("data.in","r",stdin);
144     //freopen("data.out","w",stdout);
145     scanf("%d",&T);
146     //for(int ccnt=1;ccnt<=T;ccnt++)
147     while(T--)
148     //scanf("%d%d",&n,&m);
149     //while(scanf("%s",s)!=EOF)
150     {
151         ini();
152         solve();
153         out();
154     }
155     return 0;
156 }

 

posted on 2015-02-10 10:29  njczy2010  阅读(260)  评论(0编辑  收藏  举报