牛客训练营G 机器人(状压dp||记忆化搜索)

题目链接:点这里~

题目大意

n个机器人,每个机器人会读入一个x,并返回ax+b。现在有一个x,想让你合理安排机器人顺序,使得最终返回得到的x尽可能大,输出最大值。(1<=n,x,ai,bi<=20)

思路

给的范围很小才20,那么就可以考虑到状压dp

dp[i][t]表示第i次循环在状态t的情况下出的最大值。t在二进制状态下1的位置表示该位置的机器人已经取过,比如5(101)表示1和3位置的机器人已经使用过。所以第i次循环中就枚举状态t中0的位置j,然后使用该机器人j,那么使用过机器人j之后状态就变成了t2=t|(1<<j),更新t2的状态,即dp[i][t2]=max(dp[i][t2], dp[i-1][t]*a[i]+b[i]); 初始化dp[0][0]=x,最后结果就是dp[n][(1<<n)-1],表示全都选上的最大值。

然后还可以进行记忆化搜索,当然啦,其实原理差不多,但是毕竟是记忆化搜索,少跑好多内容,时间上会节省好多,具体看代码。

需要注意的是最大值是20^20次,爆longlong了,这里使用了__int128以及他的输出函数。

ac代码

状压dp

#include<bits/stdc++.h>
using namespace std;
#define io cin.tie(0);ios::sync_with_stdio(false);
#define ok(x, y) x >= 1 && x <= n && y >= 1 && y <= m
#define debug(x) cout<<#x<<"="<<x<<endl
#define lowbit(x) x&(-x)
#define pii pair<int,int>
#define mk make_pair
#define ll long long
#define ull unsigned long long
#define lb long double
#define rs p<<1|1
#define ls p<<1
#define eps 1e-6
#define pi acos(-1)
const int maxn = 2e5 + 5;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
const int bas = 2333;
inline ll read(){
    ll p=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){p=(p<<1)+(p<<3)+(c^48),c=getchar();}
    return f*p;
}
void print(__int128 x){
    if (x<0) {putchar('-'); x=-x;}
    if (x>9) print(x/10);
    putchar('0'+x%10);
}
__int128 dp[25][1<<20];
int a[25], b[25];
void solve(){
    int n, x;
    scanf("%d%d",&n,&x);
    for(int i = 1; i <= n; i ++) 
        scanf("%d%d", &a[i], &b[i]);
    dp[0][0] = x;
    for(int i = 1; i <= n; i ++){
        for(int t = 0; t < (1 << n); t ++){
            for(int j = 0; j < n; j ++){
                if(t & (1 << j)) continue; //如果等于0,表示j位置的机器人之前已经用过了
                dp[i][t|(1<<j)] = max(dp[i][t|(1<<j)], dp[i - 1][t] * a[j + 1] + b[j + 1]); //j+1因为输入下标从1,而开始这里j是从0开始
            }
        }
    }
    print(dp[n][(1<<n)-1]); //输出,不要多输出空行,会格式错误,呜呜呜
}

int main(){
    // io;
    solve();
    return 0;
}

记忆化搜索

#include<bits/stdc++.h>
using namespace std;
#define io cin.tie(0);ios::sync_with_stdio(false);
#define ok(x, y) x >= 1 && x <= n && y >= 1 && y <= m
#define debug(x) cout<<#x<<"="<<x<<endl
#define lowbit(x) x&(-x)
#define pii pair<int,int>
#define mk make_pair
#define ll long long
#define ull unsigned long long
#define lb long double
#define rs p<<1|1
#define ls p<<1
#define eps 1e-6
#define pi acos(-1)
const int maxn = 2e5 + 5;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
const int bas = 2333;
inline ll read(){
    ll p=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){p=(p<<1)+(p<<3)+(c^48),c=getchar();}
    return f*p;
}
void print(__int128 x){
    if(x<0) {putchar('-'); x=-x;}
    if (x>9) print(x/10);
    putchar('0'+x%10);
}
__int128 dp[1<<20];
int a[25], b[25], n;
__int128 dfs(int x){
    if(~dp[x]) return dp[x]; //不是-1表示该状态先前已经跑完了,直接返回,这就是记忆化搜索!!
    for(int i = 0; i < n; i ++){
        if(!(x&(1<<i)))continue; //找到1的位置,然后x^(1<<i)表示上一个状态通过使用第i个机器人到达这个状态,然后更新x最大值
        dp[x]=max(dp[x],dfs(x^(1<<i))*a[i+1]+b[i+1]); //同理下标从1开始,而i从0开始所以需要+1
    }
    return dp[x];
}
void solve(){
    int x;
    scanf("%d%d",&n,&x);
    for(int i = 1; i <= n; i ++) 
        scanf("%d%d", &a[i], &b[i]);
    memset(dp, -1, sizeof(dp));
    dp[0] = x; //初始化
    print(dfs((1<<n)-1)); //直接输出
}

int main(){
    // io;
    solve();
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值