1 条题解

  • 0
    @ 2024-4-3 0:54:06

    【2021年省赛B组】试题G: 砝码称重

    题解

    🎉️ 动态规划,表示每个砝码的三种状态为加、减、不放, 假设题目条件简化一下,只能放一边,你会发现这不就是简单的背包吗,每个物品选和不选,最最简单的动态规划01背包的问题。

    👀️ 现在考虑能放俩边的情况,我们能不能在放一边的情况下计算呢?

    假设我们放一边的时候是不放和放的情况,那么我们跑完01背包以后怎么加上减这种情况呢?

    🚀️ 其实有个很巧妙的做法,就是把不放和加做完计算以后当成一种状态,那么和的情况当成01背包的俩种状态,如果你这个砝码用的是的这个状态,那么减去就相当于不放, 如果上次计算的状态是不放, 那么就是减去这个砝码的重量, 相当于放在天平的另一边,这样不存在重复和漏算的情况了。

    😄 结尾:顺便提一下,如果你对C++C++STLSTL库熟悉的话,可以用bitsetbitset这个简单粗暴的工具直接模拟!结尾附上代码。

    提交代码

    • 基础版本
    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N = 1e5;
    int dp[N], w[100 + 5];
    void solve()
    {
    	int n; cin >>n;
    	for(int i = 1; i <= n; i++) cin >> w[i]; 
    	memset(dp, 0, sizeof dp);
    	dp[0] = 1;
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = N; j >= w[i]; j--)
    		{
    			dp[j] = max(dp[j], dp[j - w[i]]);
    		}
    	}
    	
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= N - w[i]; j++)
    		{
    			dp[j] = max(dp[j], dp[j + w[i]]);
    		}
    	}
    	
    	int ans = 0;
    	for(int i = 1; i <= N; i++)
    	{
    		ans += dp[i];
    	}
    	std::cout << ans << "\n";
    	return;	
    }
    signed main()
    {
    	ios::sync_with_stdio(false);
    	cin.tie(0);
    	int t = 1;
    	while(t--) solve();
    	return 0;
    }
    
    • 进阶版本
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e2+7,M=1e5+7;
    bitset<M> S; //压位高精
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin.tie(0);
    	int n; cin >> n;
    	vector<int> a(n);
    	for(auto &x : a) std::cin >> x;
    	
    	S[0] = 1;
    	for(int i = 0; i < n; i++)
    	{
    		S |= S << a[i];
    	}
    	for(int i = 0; i < n; i++)
    	{
    		S |= S >> a[i];
    	}
    	cout << S.count() - 1 << "\n";
    	return 0;
    }
    
    • 1

    信息

    ID
    982
    时间
    1000ms
    内存
    256MiB
    难度
    6
    标签
    递交数
    9
    已通过
    5
    上传者