习题:小奇取石子(分类讨论)
Posted loney-s
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了习题:小奇取石子(分类讨论)相关的知识,希望对你有一定的参考价值。
题目
思路
考场上没有仔细看数据范围,导致疯狂爆炸
正解是分类讨论
也就是指对于不同的数据范围,选择不同的解法
手动滑稽
对于前(70\%)的数据
直接(O(2^n))
对于后(30\%)的数据选择DP
(dp[i][j][k])表示前i个选j堆是否能构成k
很明显i那一位可以直接省去
之后转移即可
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,m,K;
int ans=-1;
int a[205];
bool dp[205][2505];//取i堆,j的石子
bool vis[105];
void dfs(int u,int don,int step)
{
if(don>m||step>K)
return;
ans=max(ans,step);
if(u>n)
return;
dfs(u+1,don,step);
dfs(u+1,don+1,step+a[u]);
}
int main()
{
ios::sync_with_stdio(false);
//freopen("stone.in","r",stdin);
//freopen("stone.out","w",stdout);
cin>>n>>m>>K;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]<=K)
ans=max(a[i],ans);
}
if(n<=20)
{
dfs(1,0,0);
cout<<ans;
return 0;
}
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
if(a[i]>K)
continue;
for(int j=m;j>=1;j--)
{
for(int k=K;k>=a[i];k--)
{
dp[j][k]|=dp[j-1][k-a[i]];
if(dp[j][k])
ans=max(ans,k);
}
}
}
cout<<ans;
return 0;
}
以上是关于习题:小奇取石子(分类讨论)的主要内容,如果未能解决你的问题,请参考以下文章