题意:
一张纸条上依次写着N个数字,数字只可能是0或者1。在纸条上剪K刀,这样就形成了K+1段,再把这K+1段按一定的顺序重新拼起来。问前缀 1 的数量最多能是多少。
思路:
分类讨论不会啊…太菜了啊QAQ
看了题解有一种dp的做法,这比较好理解。
要把这个01串原本的前缀1剪下来只要剪1次,把原本的后缀1剪下来也要剪1次,中间的一串1剪下来要剪2次,所以这就是一个背包问题了,但是比如1101110011,如果这种策略的话要使前缀最大至少要5次,事实上只要4次,因为11100只要剪一次,放在最后面就可以了,所以事实上可以剪k+1次。
这里注意要特判全是1和k为0的情况。
代码:
char a[10010];
int w[10010];
int v[10010];
int dp[10010];
int main()
{
int n,k;
while(scanf("%d%d",&n,&k)!=EOF)
{
scanf("%s",a);
int len=strlen(a);
int s,e;
int cnt=0;
int sign=0;
for(int i=0;i<len&&sign==0;i++)
if(a[i]!='1')sign++;
if(sign==0)
{
printf("%d\n",len);
continue;
}
for(int i=0;i<len;i++)
{
if(a[i]!='1')
{
s=i;
if(i!=0)
{
v[++cnt]=i;
w[cnt]=1;
}
break;
}
}
if(k==0){printf("%d\n",v[cnt]);continue;}
for(int i=len-1;i>=0;i--)
{
if(a[i]!='1')
{
e=i;
if(i!=len-1)
{
v[++cnt]=len-1-i;
w[cnt]=1;
}
break;
}
}
int l=0;
for(int i=s;i<=e;i++)
{
if(a[i]=='0')
{
if(l!=0)
{
v[++cnt]=l;
w[cnt]=2;
}
l=0;
}
else l++;
}
//for(int i=1;i<=cnt;i++)
//printf("%d %d\n",w[i],v[i]);
memset(dp,0,sizeof(dp));
for(int i=1;i<=cnt;i++)
{
for(int j=k+1;j>=w[i];j--)
{
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
printf("%d\n",dp[k+1]);
}
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!