OK,拿到这道题的时候思路还是蛮清晰的,因为可以非常明显的发现就是不断更改减法的顺序其实并没有改变序列中的值,而仅仅改变的是这个数之前的加或者减(加变减,减变加)所以,问题变成了求一个合法的添加加减顺序使得整个数列得到想要的答案。
这里有参考其他题解:
首先定义 f[ i ][ j ]表示前i个数为止通过加减能否得到j这一个数,如果答案为1则表示通过减得到2就表示 通过加得到0表示无法得到
最后就是答应路径,一开始以为挺麻烦的,后来发现并不是这么一回事,自己在草稿纸上多演算几次就可以发现一个规律:如果前面是+就一定要先运算最后剩下的全部输出1就ok了
最后,有一个地方坑了我几次,就是
if()
else if()
原来直接用的事两个if 而后来发现j是不断更新的一开始不满足的条件更新后可能会满足,总之多用else
#include<cstdio>
#include<cstring>
#include<iostream>
#define fix 10000
using namespace std;
int n , m , f[125][20020],pre[122],cur[122];
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=1;i<=n;i++)scanf("%d",cur+i);
memset(f,0,sizeof(f));
memset(pre,0,sizeof(pre));
f[2][cur[1]-cur[2]+fix]=1;
for(int i=3;i<=n;i++){
for(int j=0;j<=20000;j++){
if(f[i-1][j]>0){
if(j+cur[i]<=20000)f[i][j+cur[i]]=2;
if(j-cur[i]>=0)f[i][j-cur[i]]=1;
}
}
}
for(int i=n,j=m+fix;i>=1;i--){
if(f[i][j]==1){
pre[i]=1;
j+=cur[i];
}
else if(f[i][j]==2){
pre[i]=2;
j-=cur[i];
}
}
int cnt=0;
for(int i=2;i<=n;i++){
if(pre[i]==2){
printf("%d\n",i-cnt-1);
cnt++;
}
}
for(int i=2;i<=n;i++)if(pre[i]==1)puts("1");
}
return 0;
}
本文介绍了一种解决特定数列加减法问题的方法,通过动态规划算法确定数列中元素的加减顺序,以达到目标值。文章详细解释了状态转移方程,并提供了完整的C++代码实现。

1519

被折叠的 条评论
为什么被折叠?



