洛谷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;
}
posted @ 2022-01-30 16:01  Sun-Wind  阅读(45)  评论(0编辑  收藏  举报