版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39562952/article/details/84777479
思路:
先说什么是状压dp(一开始我也不知道,但是做了一次之后发现还挺简单的),一句话概括就是一种很暴力的dp方式;
核心思想是:枚举所有的情况,用二进制记录状态
这道题其实只要枚举所有状态,并且是根据前面的状态推导得到,如:
用(111)表示三门课都完成,则这个状态有可能是从(110),(101),(011)这三种状态推出;
代码如下:
#include<cstdio>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
struct node1
{
char name[100];
int cost;
int dead;
}work[20];//每个任务
struct node2
{
int fa;//父节点
int reduce; //要扣的分数
int cost;//完成当前状态要的时间
int nowbook;//当前状态比父状态多完成了哪一门课
}dp[1<<16];//完成当前状态要扣的最少分数
int n;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s%d%d",work[i].name,&work[i].dead,&work[i].cost);
}
int end=1<<n;
for(int i=1;i<end;i++)
{
dp[i].reduce=inf;
for(int j=n-1;j>=0;j--)
{
int temp=1<<j;
if(temp&i)//说明这个状态要完成的是j这门课
{
int ttemp=i-temp;//代表上个状态
int reduce=work[j].dead-dp[ttemp].cost-work[j].cost;//当前状态要扣的分数
reduce*=(-1);
if(reduce<0)
{
reduce=0;
}
if(dp[ttemp].reduce+reduce<dp[i].reduce)
{
dp[i].fa=ttemp;
dp[i].reduce=dp[ttemp].reduce+reduce;
dp[i].nowbook=j;
dp[i].cost=dp[ttemp].cost+work[j].cost;
}
}
}
}
printf("%d\n",dp[end-1].reduce);
int ans[100];
int x=0;
int t=end-1;
while(t)
{
ans[x++]=dp[t].nowbook;
t=dp[t].fa;
}
for(int i=x-1;i>=0;i--)
{
printf("%s\n",work[ans[i]].name);
}
}
return 0;
}