原题链接:E-小红的子集取反_牛客周赛 Round 31 (nowcoder.com)
题目大意:小红拿到了一个数组,她准备选择若干元素乘以 -1,使得最终所有元素的和为 0。小红想知道最少需要选择多少个元素?
思路:此问题类似与01背包,每个数只能操作一次,每次操作的代价可以记为1。
y总的dp分析方法可得到:
直接看代码吧
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pii;
const int N=1e6+10;
ll n,f[220][80020];
int main()
{
ios::sync_with_stdio(NULL);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=0;i<=200;i++)
{
for(int j=0;j<=80000;j++)
{
f[i][j]=1e18;
}
}
f[0][40000]=0;
ll x;
for(int i=1;i<=n;i++)
{
cin>>x;
for(int j=0;j<=80000;j++)
{
if(j-x>=0&&j-x<=80000)f[i][j]=min(f[i][j],f[i-1][j-x]);//这个是图中状态转移的左边
if(j+x>=0&&j+x<=80000)f[i][j]=min(f[i][j],f[i-1][j+x]+1);//这是图中状态转移的右边
}
}
if(f[n][40000]!=1e18)cout<<f[n][40000];
else cout<<-1;
return 0;
}
附上一份dfs的代码(别用map会T!!!):
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pii;
const int N=1e6+10;
ll p[N],n;
ll op[220][80800];
ll dfs(ll x,ll k)
{
if(op[x][k]!=0x3f3f3f3f3f3f3f3f)return op[x][k];
if(x>n)
{
if(k==0)return 0;
else return 1e18;
}
ll sum=0;
sum=min(dfs(x+1,k+p[x]),dfs(x+1,k-p[x])+1);
op[x][k]=sum;
return sum;
}
int main()
{
ios::sync_with_stdio(NULL);
cin.tie(0),cout.tie(0);
cin>>n;
memset(op,0x3f,sizeof(op));
for(int i=1;i<=n;i++)cin>>p[i];
ll k=dfs(0,0);
if(k==1e18)cout<<-1;
else cout<<k;
return 0;
}