Gym 100712D Alternating Strings 动态规划

来源:互联网 发布:华为财务共享中心 知乎 编辑:程序博客网 时间:2024/05/19 22:55

题意:给你一个n值一个k值,一个长度为n01串,现在要求你切割原串,使新形成的每个子串都满足,长度不超过k,且任何子串都不是完全交替的01串,利于010101就是完全交替的01串,而00101010就不是,问你最少需要切几刀。

 

题解:完全照着官方题解来的,自己看了几个小时也没看明白,问巨巨们都是扫一眼就告诉我怎么做,然而即便是这样我还是无法理解每一步程序究竟是什么意思,后来跟phy讨论了半天,慢慢慢慢才搞懂了。

虽然这貌似在大神们眼里是个很简单的dp,但是既然卡了我这么久,那还是好好理下思路。

首先,题解里的外循环i是从后往前推的,然后内循环是从第i位向后推k位。当然这两个循环是完全可以调头的(i从前往后,内循环从i往前推k位)这些都无所谓。

dp[i]代表的是从第i位开始往后的串在满足条件的情况下切完后所形成的子串数目。

下面就开始讲解dp的递推过程。

假设一个串11100k3,那么我们从右往左推首先初始化dp[5]=0,因为s下标从0n-1,所以相当于第5位没东西,自然没有一个串。

接下来进入循环。

I=4,则j4开始到mins.len,i+l-1)即第4位,当i==j时,dp[4]=dp[5]+1

那么这个dp[5]+1是什么意思呢,我们知道dp[5]=0代表第五位没有串。那么dp[5]+1即,在第五位的基础上加了一个串进去,也就是s[4]。那么此时dp[4]=1就代表有了一个合法的串。

I=3,j3开始到mins.len,i+l-1)即第4位,先是dp[3]=dp[4]+1=2,即在段s[4]外加了一个段s[3].

就是这样0,红色的零就是我们当前加进去的串。然后当j=4时,因为s[j]=s[j-1]=0,所以,s[j]s[j-1]所构成的串为合法串,那么它们俩就可以单独构成一个串。也就是说可以合起来放在第5位外面,即0 0,这样dp[i]就可以取1。取最优解。

I=2时,j24,同样dp[2]=dp[3]+1=2,代表这样,1 0 0,而当j=3时,因为s[j]!=s[j-1],所以从s[j]s[j-1]所构成的串是不合法的,所以我们不能把他们俩组合起来加在第4位的外面(也就是这样1 0 0),所以不进行比较,而当j=4时,因为s[j]==s[j-1]=0,此时dp[i]=min(dp[i],dp[j+1]+1)也就是把100连起来放在了第5位外面,拿这种情况(100)跟(100)相比,取最优解(100dp[2]=1;

以下红色都为当前i到j之间的串。

I=1时,

J=1先是这样1 1 0. . . 

J=2 1 . . . 

J=3  1 1 0 . . .(因为前面出现过11,所以0可以加在11后面形成合法串)

取最优解 1 1 0 . . .

I=0

J = 0  1 1 . . . 

J = 1  1 1 ....

J= 2   1 1 1 ....

取最优解

那么最后dp[0]即为最少段数,dp[0]-1就是最少切割次数。

 

果然,蒟蒻就要多写写尽量写完整才能把思路理清。

 

代码(其实就是官方题解):

#include<bits/stdc++.h>#define MEM(a,x) memset(a,x,sizeof(a));#define MEMINF(a) memset(a,0x3f,sizeof(a));using namespace std;typedef long long LL;const int MAXN=205;const int INF=0x3f3f3f3f;const int MOD=1000000007;int dp[MAXN];int main() {  int T;  cin>>T;  while (T--) {  int n,k;  string s;  cin>>n>>k>>s;  dp[n]=0;  for (int i=s.size()-1; i>=0; i--) {    bool flag=true;    dp[i]=INF;    for (int j = i; j <= i + k - 1 && j < s.size(); ++j) {      if ( j > i && s[j] == s[j - 1])        flag = false;      if (i == j || flag == false )         dp[i]= min(dp[i], 1 + dp[j + 1]);    }  }  printf("%d\n",dp[0]-1);}}


 

2 0
原创粉丝点击