A. Acing the contest 状压dp 背包

A common programming contest format includes teams with three contestants working to solve the maximum amount of programming challenges in the less amount of time using a single computer. Some contests have been created using a similar idea. In this contest a team has T team members, each team member has an energy Ei. The higher the energy of the member the more and the harder problems he can solve. There are a total of P programming challenges, to be solved, using a single computer. The programming challenges are numbered with numbers from 1 to P, each one having a difficulty of Di and a score value of Si.

The contest runs as follows, the first team member will sit in front of the computer and then the contest will start , then the first problem will be shown to him, he has to decide either to solve the problem, to do not solve it and go try the next one, or to stop solving problems. A team member can solve a problem if and only if it’s remaining energy is grater or equal to the problem difficulty. Once the team member decides to stop solving problems, he can not solve problems again and the next team member will sit in front of the computer and start with the problem the previous team member left. If the team member i solves problem j, then it will take Dj from his Ei energy and score Sj points to the team. If a team member decides to not solve a problem and go to the next one, no other member in the team can go back to solve it. The contest ends for the team when either there are no more problems to solve, or there are no team members left to work on the remaining problems.

For this particular problem your task is, given the energy of each team member, the difficulty and score of the problems in a contest, determine in what order the team members should solve the problems so the team can score their maximum possible score.

Input
The first line of input contains two integer numbers separated by a space T and P (1≤T≤10, 1≤P≤100), representing, respectively, the number of team members in the team, and the number of problems in the contest. The next line contains T integer numbers separated by a space, where the i-th number represents the energy Ei (1≤Ei≤100) of the team member. The next line contains P integer numbers separated by a space, where the i-th number represents the difficulty Di (1≤Di≤100) of the i-th problem in the contests, the next and last line of input contains P integer number separated by a space, where the i-th number represents the score Si (1≤Si≤100) the i-th problem gives to the team if they solve it.

Output
Output a line with a single integer number, the maximum possible score the team can obtain.

Example
inputCopy
3 3
4 2 5
2 2 5
3 2 1
outputCopy
6

题意:给你t个队员,p个问题,每个问题有需要的能量和贡献,每个队员有自己的能量值,现在让你可以随意给队员排序,让他们按顺序A题,前面的人不写的题后面的人也写不了,问你最大贡献。

思路:设dp[i][j]为i所表示的二进制集合中,写到第j题的最大贡献。其中i就是一个表示有哪几个人上机写题的集合,如011,就是第三个人没写题,第一个和第二个人写了题的集合表示。
那么状态转移方程如何确定呢?对于dp[i][j]状态,他的下一个状态就是i集合里面,找到一个为0的位,把它置为1(相当于这个人现在上机写题了),从第j题开始写到第k题(k从j到p)。所以状态转移方程就可以看成是:
d p [ n e x t S t a t e ] [ k ] = m a x ( d p [ n e x t S t a t e ] [ k ] , d p [ i ] [ j ] + 这 一 位 的 人 从 第 j 题 开 始 写 到 第 k 题 最 优 解 A n s dp[nextState][k] = max(dp[nextState][k], dp[i][j] + 这一位的人从第j题开始写到第k题最优解Ans dp[nextState][k]=max(dp[nextState][k],dp[i][j]+jkAns)
而Ans怎么求?思考一下便发现其实这就是一个普通的01背包问题,只是不是从第一个物品开始选,而是从第j个物品开始选。这一步我们可以先预处理完成。

思路大概简述这么多,主要还是看代码注释吧

AC代码:

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define endl '\n'
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 1e5+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };

ll T[15];
ll n;

typedef struct Pro
{
    ll D;
    ll S;
}P;

P a[105];

int dp[1<<10][102]; //dp[i][j][k] 表示i集合表示的人中,写到第j题的最优解
int dp1[102][102][102];  //dp1[i][j][k] 表示从第i题开始,做到第j个问题时,能量还剩k点时的最优解
int ok[1<<10][102];

int main()
{
    ll t = read(), p = read();
    rep(i,1,t) T[i] = read();
    rep(i,1,p) a[i].D = read();
    rep(i,1,p) a[i].S = read();

    rep(s,1,p)  //先预处理得到第s题开始,做到第j个问题时,能量还剩k点时的最优解
    {
        rep(k,1,100) rep(j,s,p)
        {
            dp1[s][j][k] = max(dp1[s][j][k-1],dp1[s][j-1][k]);
            if(k>=a[j].D&&dp1[s][j-1][k-a[j].D]+a[j].S>dp1[s][j][k])
            dp1[s][j][k] = dp1[s][j-1][k-a[j].D]+a[j].S;
        }
    }

   ll ma = 0;
    rep(i,0,(1<<t)-1) rep(j,1,p)        //核心代码,对于dp[i][j],
    {
        rep(last,1,t) if(!((i>>(last-1))&1))    //可以找到一个还没加入集合的人,让他来上机写题
        {
            int nextState = i + (1<<(last-1));  //下一个状态就是把他加上
            int s = ok[i][j]?j+1:j;     //开始位置,取决于j这个位置有没有被选上
            rep(k,s,p)      //看看当前这个人从第j题出发写写到第k题最优解是什么
            {
                if(dp[nextState][k] < dp1[s][k][T[last]] + dp[i][j])
                {
                    dp[nextState][k] = dp1[s][k][T[last]] + dp[i][j];
                    ok[nextState][k] = 1;
                    ma = max(ma,dp[nextState][k]);
                }
            }
        }
    }
    cout<<ma<<endl;
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值