POJ 2923 Relocation (状压DP+背包)

题目大意

这里有两辆车,每个车各自能装一定重量的物品,这里有N个物品,物品有各自的重量,每次要用两个车一起运物品,问你最少运的次数。

思路:

先预处理出来那个状态一次是可以运送的,把这些状态储存到sta的这个数组。

剩下的背包一下就差不多了,这里背包的是状态,状态转移方程式是:

dp[ j | sta[i] ]=min( dp[j | sta[i] ] , dp[j]+1)

AC代码:

/* ***********************************************
Author        :yzkAccepted
Created Time  :2016/3/22 18:55:01
TASK		  :ggfly.cpp
LANG          :C++
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
typedef __int64 ll;
const int INF=1<<27;
int dp[1<<11];
int sta[1<<11];
int cost[1<<12];
bool vis[1<<11];
int n,c1,c2;
int judge(int x)
{
	memset(vis,false,sizeof(vis));
	int summ=0;
	vis[0]=true;
	int i,j;
	for(i=0;i<n;i++)
	{
		if((1<<i)&x)
		{
			summ+=cost[i];
			for(j=c1;j>=cost[i];j--)
			{
				if(vis[j-cost[i]])
				{	
					vis[j]=true;
				}
			}

		}
	}
	if(summ>c1+c2)
		return 0;
	for(i=0;i<=c1;i++)
		if(vis[i]==1&& summ-i<=c2)
			return 1;
	return 0;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int cas,t,tot;
	scanf("%d",&t);
	cas=0;
	int i,j,sum;
	while(t--)
	{
		tot=0;
		cas++;
		scanf("%d",&n);
		scanf("%d%d",&c1,&c2);
		for(i=0;i<n;i++)
			scanf("%d",&cost[i]);
		sum=(1<<n)-1;
		for(i=0;i<=sum;i++)
			dp[i]=INF;
		dp[0]=0;
		for(i=1;i<=sum;i++)
			if(judge(i)==1)
				sta[tot++]=i;//预处理一下所有可能的状态
		for(i=0;i<tot;i++)
		{
			for(j=sum;j>=0;j--)
			{
				if(dp[j]==INF)
					continue;
				if((sta[i] & j)==0)
				{
					dp[j|sta[i]]=min(dp[j|sta[i]],dp[j]+1);
				}
			}
		}
		printf("Scenario #%d:\n%d\n\n",cas,dp[sum]);
	}
    return 0;
}


你可能感兴趣的:(poj)