题目链接:点这里~
题目大意
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;
}