HDU1074:Doing Homework(状压DP)

リンク

質問の意味:割り当て、割り当ての期限、および割り当てを完了するのに必要な時間をいくつか教えてください。ただし、割り当てがその期限を超えると、1ポイントが差し引かれます。控除が最も少ない場合は、割り当ての順序をどのように調整するかを尋ねてください。この種のソリューションは、最小の辞書式順序でソリューションを出力することであり、これらのジョブが指定されると、辞書式順序は昇順になります。

アイデア:ジョブは最大15個しかないため、dpを押して、dp [i] [j]を最後に完了したジョブをi、完了したジョブのステータスをj、次に完了するジョブを列挙して、これらの完了を計算します。ジョブに必要な合計時間はkとして記録され、転送はdp [次へ] [j |(1 <<次へ]] = min(dp [i] [j] + finsh(j)+ a [次へ] .f-a [next] .d)(nextはjにないジョブです)。答えはmin(dp [1—n] [(1 << n)-1])で、コードによっては、印刷パスという別の問題があります。

#include <bits/stdc++.h>
#define ll long long
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
using namespace std;
const int inf = 2e9+100;
struct node {
	int d,f;
	string name;
}a[16];
int dp[16][1<<16],pre[16],n;
int count(int s)
{
	int ans = 0;
	for(int i=0;i<n;i++)if((1<<i&s))ans+=a[i].f;
	return ans;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		scanf("%d",&n);
		for(int i=0;i<n;i++)cin>>a[i].name>>a[i].d>>a[i].f;
		memset(dp,inf,sizeof(dp));
		for(int i=0;i<n;i++)dp[i][1<<i] = max(0,- a[i].d + a[i].f);
		
		for(int s=1;s<1<<n;s++)
		for(int i=0;i<n;i++)
		if((s&(1<<i))!=0)
		for(int j=0;j<n;j++)
			if((1<<j&s)==0) {
				if(dp[j][s|(1<<j)] > dp[i][s] + max(0 , (count(s)+a[j].f-a[j].d)))
				dp[j][s|(1<<j)] = dp[i][s] + max(0 , (count(s)-a[j].d+a[j].f));
			}
	
		int id=0,ans = inf;
		for(int i=0;i<n;i++)
			if(dp[i][(1<<n)-1] <= ans)
			{
				ans = dp[i][(1<<n)-1];
				id = i;
			}
		cout<<ans<<'\n';
		int sta = (1<<n)-1;
		stack<int>s;
		while(sta)
		{
			s.push(id);
			sta-=(1<<id);
			ans = inf;
			for(int i=0;i<n;i++)
				if(dp[i][sta] <= ans)
				{
					ans = dp[i][sta];
					id = i;
				}
		}
		while(!s.empty())
		{
			cout<<a[s.top()].name<<'\n';
			s.pop();
		}
	}
	return 0;
}

 

おすすめ

転載: blog.csdn.net/weixin_44499508/article/details/105555399