hdu1074(状压dp)

版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
} 

猜你喜欢

转载自blog.csdn.net/qq_39562952/article/details/84777479
今日推荐