题意:给一个长度为n的01序列,现让你从这个序列中删除一些数字,使得1后面没有0,求这个序列最多还剩多少个数字
思路:
一开始题意理解错了,以为只能删除0,于是wa了几发。。。
这道题有两种做法。。。
脑洞和思维:
先存在a[n]里面,遍历a[n],对于a[i]如果是0则不删除,如果是1则删除,定义最后可以剩余的个数为sum,每次取sum的最大值那么对这两种情况进行讨论
1.a[i]=0,不删,显然sum要加上i和i之前0的个数,然后加上i之后1的个数
2.a[i]=1,删,显然sum要加上i之前0的个数,然后加上i之后1的个数
加之前的0比较好理解,但是为什么只加之后的1呢?这样不会错解吗。
对于第一种情况,假如紧跟着i的是0,那么i循环到i+1的时候必然会有sum_(i+1)>sum_i,即一定可以在后面得到正解,如果紧跟着i的是1那么可以在第二种情况得到正解
对于第二种情况又可以转换到第一种
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <stack>
#define INF 0x3f3f3f3f
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
int n;
int a[105];
int main()
{
while(~scanf("%d", &n))
{
int cnt=0;
for(int i=0; i<n; i++)
{
scanf("%d", &a[i]);
cnt+=a[i];
}
for(int i=0; i<n; i++)
{
int sum=0;
for(int j=0; j<n; j++)
sum+=(j<=i?!a[j]:a[j]);
cnt=max(cnt, sum);
}
printf("%d\n", cnt);
}
return 0;
}
动态规划:
可以设置dp[i][j]是前i个数中以j为结尾所满足的序列的最大长度
那么可以根据第i位的值来进行决策,具体看代码
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <stack>
#define INF 0x3f3f3f3f
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
int n;
int a[105];
int dp[105][2];
int main()
{
while(~scanf("%d", &n))
{
memset(a, -1, sizeof(a));
for(int i=0; i<n; i++)
scanf("%d", &a[i]);
memset(dp, 0, sizeof(dp));
if(a[0])
dp[0][1]=1;
else
dp[0][0]=1;
for(int i=1; i<n; i++)
{
if(a[i]) //根据a[i]的值进行决策
{
dp[i][1]=max(dp[i-1][1], dp[i-1][0])+1;
dp[i][0]=dp[i-1][0];
}
else
{
dp[i][1]=dp[i-1][1];
dp[i][0]=dp[i-1][0]+1;
}
}
printf("%d\n", max(dp[n-1][0], dp[n-1][1]));
}
}