POJ 状态DP+ 01 背包问题

题目大意: n  个货物 用两辆汽车运走 货车的 容量 为 c1  c2 问 至少需要多少次才能运完。

本人菜鸟:开始思路是看的网上的基本代码如下

基本思路:

/*
 * 状态 DP + 01背包
 * 题目大意:给定n个物品和两辆车的最大运载量,每次两辆车都要同时开动,问最少开几次能把所有物品运走,1<=n<=10.
 * 解题思路:好题,解法为状态压缩DP+背包,我的状态压缩DP做的特别少,所有在看到本题的n的范围时还没能很敏感地往状态压缩方面想。本题的解题思路是先枚举选择若干个时的状态,总状态量为1<<n,判断这些状态集合里的那些物品能否一次就运走,如果能运走,那就把这个状态看成一个物品。预处理完能从枚举中找到tot个物品,再用这tot个物品中没有交集(也就是两个状态不能同时含有一个物品)的物品进行01背包,每个物品的体积是state[i],价值是1,求包含n个物品的最少价值也就是dp[(1<<n)-1](dp[i]表示状态i需要运的最少次数)。
 * 状态转移方程:dp[j|k] = min(dp[j|k],dp[k]+1) (k为state[i,1<=j<=(1<<n)-1])。算法复杂度O((2^N)*N)
 */

 

import java.util.Scanner;
/*
 * 状态 DP + 01背包 
 * 题目大意:给定n个物品和两辆车的最大运载量,每次两辆车都要同时开动,问最少开几次能把所有物品运走,1<=n<=10.
 * 解题思路:好题,解法为状态压缩DP+背包,我的状态压缩DP做的特别少,所有在看到本题的n的范围时还没能很敏感地往状态压缩方面想。本题的解题思路是先枚举选择若干个时的状态,总状态量为1<<n,判断这些状态集合里的那些物品能否一次就运走,如果能运走,那就把这个状态看成一个物品。预处理完能从枚举中找到tot个物品,再用这tot个物品中没有交集(也就是两个状态不能同时含有一个物品)的物品进行01背包,每个物品的体积是state[i],价值是1,求包含n个物品的最少价值也就是dp[(1<<n)-1](dp[i]表示状态i需要运的最少次数)。
 * 状态转移方程:dp[j|k] = min(dp[j|k],dp[k]+1) (k为state[i,1<=j<=(1<<n)-1])。算法复杂度O((2^N)*N)
 */
public class POJ2923 {
	int cases, n, c1, c2;
	int [] w;
	int ok[];
	int tol = 0; // 总共能行的状态
	int  [] dp;
	static int inf = 1<<30;
	/*
	 * 判断状态 state 是否能一次性运走
	 */
	public boolean judge(int state) {
		int f[] = new int[c1+1];
		int sum = 0;
		for(int i=0; i<n; i++){
			int tem = 1<<i; 
			//System.out.println(tem);
			if( (state &(tem)) != 0){// 如果 定 i 个物品 选择
				sum += w[i];
				f[0] = 1;
				for(int c=c1; c>=w[i]; c--){ // 选择最大 放入 到  c1 车中 0 1 背包
					f[c] = Math.max(f[c], f[c-w[i]]);
				}
			}
		}
		if( sum > c1 + c2){
			return false;
		}
		for(int i=0; i<=c1; i++){
			if(f[i] !=0 && sum - i <= c2){
				return true;
			}
		}
		return false;
	}
	public void solve(){
		Scanner sc = new Scanner(System.in);
		cases = sc.nextInt();
		for(int i=0; i<cases; i++){
			n = sc.nextInt(); c1 = sc.nextInt(); c2 = sc.nextInt();
			w = new int[n]; ok = new int[1<<10]; dp = new int[1<<n];
			tol = 0;
			for(int j=0; j<n; j++){
				w[j] = sc.nextInt();
			}
			for(int k = 1; k<(1<<n); k++){
				dp[k] = inf;
				if(judge(k)){
					ok[tol] = k; tol ++;
				}
			}
			dp[0] = 0;
			for(int j=0; j<tol; j++){// 0 1 背包  有 tol 个物品
				for(int k=0; k<(1<<n); k++){
					if( dp[j] == inf) continue;
					int t = ok[j] + k;
					if( t != (k |ok[j])) continue; // 如果两种状态 冲突
					dp[t] = Math.min(dp[t], dp[k]+1);// 
				}
			}
			System.out.println("Scenario #"+(i+1)+":\n"+dp[(1<<n)-1]);
			System.out.println("");
		}
	}
	public static void main(String[] args) {
		new POJ2923().solve();
	}
}


 

 

 


 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值