poj 2923 Relocation(狀態壓縮+01揹包)

思路:總共有2^10的狀態,枚舉每一個狀態用01揹包判斷是否此狀態可以一次運走,並記錄下來,接下來又用每一個可以一趟就運走的狀態看成一個01揹包問題中要裝的物品,求出最小的運送的次數。

#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define CL(a,b) memset(a,b,sizeof(a))
#define MIN(a,b) a<b?a:b
#define MAX(a,b) a>b?a:b
using namespace std;
const int M(107);
int c1,c2,a[M],f[M],n;
int state[1200],dp[1200];
inline bool judge(int s)
{
	int i,sum=0,j;
	CL(f,0);
	for(i=0;i<n;i++)
		if(s&(1<<i))
		{
			sum+=a[i];
			for(j=c1;j>=a[i];j--)
				f[j]=MAX(f[j-a[i]]+a[i],f[j]);
		}
	if(sum-f[c1]<=c2)return true;
	return false;
}
int main()
{
	int t,i,j,k,l;
	scanf("%d",&t);
	for(l=1;l<=t;l++)
	{
		scanf("%d%d%d",&n,&c1,&c2);
		if(c1<c2)swap(c1,c2);
		for(i=0;i<n;i++)
			scanf("%d",&a[i]);
		for(i=0,k=0;i<(1<<n);i++)
		{
			if(judge(i))state[k++]=i;//記錄兩輛車一趟可以運走的狀態。
			dp[i]=100000000;
		}
		dp[0]=0;
		for(i=0;i<k;i++)
			for(j=(1<<n)-1;j>=0;j--)
					if(!(j&state[i]))//去除重複覆蓋(重複運送同一個物品)
						dp[j|state[i]]=MIN(dp[j|state[i]],dp[j]+1);

		printf("Scenario #%d:\n",l);
		printf("%d\n",dp[(1<<n)-1]);
		if(l!=t)
			printf("\n");
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章