洛谷1441
这道题也是最近写的比较好的题,给了我很多的收获
- 填表法 :就是一般的动态规划,当前点的状态,可以直接用状态方程,根据之前点的状态推导出来。
- 刷表法:由当前点的状态,更新其他点的状态。需要注意:只有当每个状态所依赖的状态对它的影响相互独立。
一般的01背包就是用的填表法解决问题,刷表法目前看来主要是计数类的题比较多
这道题所用到的剪枝策略也让人受益匪浅
此题还解决了n个数的组成情况问题
之前帖主用的dfs由于剪枝不当,只过了60%点
void dfs(int x){
if(x == m) {
pack();
// fi(i,0,m-1) cout << rem[i] << " ";
// cout << endl;
return;
}
fi(i,1,n){
if(!vis[i]){
rem[x] = i;
vis[i] = true;
dfs(x+1);
vis[i] = false;
}
}
}
上面是之前写的dfs,可见这个dfs求得是排列数,分支数太多,导致最后得时间复杂度已经接近了指数级别
这个时间复杂度大致是mAmnpack()
下面剪枝得时间复杂度为nm-m m/2+m * pack();
主要得时间复杂度显然和最后处理得pack函数有关
#include <iostream>
#include <utility>
using namespace std;
typedef long long ll;
#define fi(i, a, b) for (int i = a; i <= b; ++i)
#define fr(i, a, b) for (int i = a; i >= b; --i)
#define x first
#define y second
#define sz(x) ((int)(x).size())
#define pb push_back
using pii = pair<int, int>;
//#define DEBUG
int wei[25];
int rem[5];
bool vis[25];
int n, m;
bool dp[2010];
int ans, res;
void pack()
{
ans = 0;
int tot = 0;
fi(i, 1, n * 100 + 9) dp[i] = false;
dp[0] = true;
fi(i, 1, n)
{
fr(j, tot, 0)
{
if (vis[i])
break;
if (dp[j] && !dp[j + wei[i]])
{
dp[j + wei[i]] = true;
ans++;
}
}
if (!vis[i])
tot += wei[i];
}
res = max(res, ans);
}
void dfs(int x, int y)
{
if (y == m + 1)
return;
if (x == n + 1)
{
if (y == m)
{
pack();
}
return;
}
dfs(x + 1, y);
vis[x] = true;
rem[y] = x;
dfs(x + 1, y + 1);
vis[x] = false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
fi(i, 1, n) cin >> wei[i];
dfs(1, 0);
cout << res << endl;
#ifdef DEBUG
//freopen(D:\in.txt,r,stdin);
#endif
return 0;
}
看到评论区还有大佬用的状态压缩+二进制的方法
#include<iostream>
#include<utility>
#include<bitset>
using namespace std;
typedef long long ll;
#define fi(i,a,b) for(int i = a; i <= b; ++i)
#define fr(i,a,b) for(int i = a; i >= b; --i)
#define x first
#define y second
#define sz(x) ((int)(x).size())
#define pb push_back
using pii = pair<int,int>;
//#define DEBUG
int w[25];
int n,m;
int res;
int count_1(int x){
int cnt = 0;
fi(i,0,n-1){
if(x & 1 << i) cnt++;
}
return cnt;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
fi(i,0,n-1) cin >> w[i];
fi(i,0,(1 << n) - 1){
if(count_1(i) == n - m){
bitset<2010> state;
state[0] = 1;
fi(j,0,n-1){
if(i & 1 << j){
state = state | state << w[j];
}
}
res = max(res,(int)state.count());
}
}
cout << res - 1 << endl;
#ifdef DEBUG
//freopen(D:\in.txt,r,stdin);
#endif
return 0;
}