2023.3.14 状压 dp 模拟赛题解

好强啊。


image

首先 T1 的一个优化 luogu P1842 奶牛玩杂技,需要一个贪心排序来优化序列顺序。关于贪心排序:像这样有两种及以上性质的序列,注意以哪个为关键字排列。两道题的顺序都是:x.s + x.w > y.s + y.w。一定会优先选又重又强壮的奶牛垫在下面。

两种做法:1.dfs。爆搜加上各种优化剪枝就会把时间复杂度降到很小。代码是找同学要的,太强了我今天才刚会写 dfs,这种剪枝第一次见真就叹为观止!

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 22;
int n, flag = 0;
ll h, ans = 0;
int sumh[N], sumw[N];
struct Cow {ll h, w, s;} a[N];

bool cmp(Cow x, Cow y){return x.s + x.w > y.s + y.w;}

void dfs(int i, ll high, ll tot)
{
    if(high >= h)
    {
        flag = 1;
        ans = max(ans, tot);
        return ;
    }
    if(i > n) return ;
    if(ans >= tot) return ;
    if(high + sumh[n] - sumh[i - 1] < h) return ;
    if(a[i].w <= tot) dfs(i + 1, high + a[i].h, min(a[i].s, tot - a[i].w));
    if(tot) dfs(i + 1, high, tot);
}

int main()
{
    scanf("%d%lld", &n, &h);
    for(int i = 1; i <= n; i ++ ) scanf("%lld%lld%lld", &a[i].h, &a[i].w, &a[i].s);
    sort(a + 1, a + n + 1, cmp);
    for(int i = 1; i <= n; i ++ )
    {
        sumh[i] = sumh[i - 1] + a[i].h;
        sumw[i] = sumw[i - 1] + a[i].w;
    }
    dfs(1, 0, 0x3f3f3f3f);
    if(flag) printf("%lld", ans);
    else printf("Impossible");
    return 0;
}

2.状态压缩 dp

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=21;
const int inf=0x3f3f3f3f;
int n;
ll m, tot, maxn = -1;
int r[N];
struct node {ll h,w,s;} a[N];
bool cmp(node a,node b) {return a.s + a.w > b.s + b.w;}
ll check()
{
    ll sum = 0, high = 0, ans = inf;
    for(int i = 1; i <= tot; i ++ )
    {
        sum = 0;
        for(int j = i + 1; j <= tot; j ++ ) sum += a[r[j]].w;
        if(sum > a[r[i]].s) return -1;
        high += a[r[i]].h;
        ans = min(ans, a[r[i]].s - sum);
    }
    if(high < m) return -1;
    return ans;
}
int main()
{
    scanf("%d%lld",&n,&m);
    for(int i = 0; i < n; i ++ ) scanf("%lld%lld%lld", &a[i].h, &a[i].w, &a[i].s);
    sort(a, a + n, cmp);
    for(int s = 1; s < 1 << n; s ++ )
    {
        tot = 0;
        for(int i = 0; i < n; i ++ ) if(s & 1 << i) r[ ++ tot] = i;
        maxn = max(maxn, check());
    }
    if(!maxn) printf("Impossible\n");
    else printf("%lld", maxn);
    return 0;
}
posted @ 2023-03-14 20:51  Moyyer_suiy  阅读(16)  评论(0编辑  收藏  举报