状态压缩DP+枚举子集 BZOJ2073 过桥

今天更状态压缩的一支,要枚举子集的DP算法;

题目:
 一只队伍在爬山时碰到了雪崩 , 他们在逃跑时遇到了一座桥 , 他们要尽快的过桥 . 桥已经 很旧了 , 所以它不能承受太重的东西 . 任何时候队伍在桥上的人都不能超过一定的限 制 . 所以这只队伍过桥时只能分批过 , 当一组全部过去时 , 下一组才能接着过 . 队伍里每个 人过桥都需要特定的时间 , 当一批队员过桥时时间应该算走得最慢的那一个 , 每个人也有 特定的重量 , 我们想知道如何分批过桥能使总时间最少 .
 Input
 第一行两个数 : w —— 桥能承受的最大重量 (100 <= w <= 400) 和 n —— 队员总数 (1 <= n <= 16). 接下来 n 行每行两个数分别表示 : t – 该队员过桥所需时间 (1 <= t <= 50) 和 w – 该队员的重量 (10 <= w <= 100).
 Output
 输出一个数表示最少的过桥时间 .

样例输入 :

100 3

24 60

10 40

18 50

样例输出    42


这道题目要先枚举出人员的分组数,再对每组进行动态规划算出最短时间。分组用16位(最多16个队员)的2进制来表示,比如说:10110  5个位,3名队员编号分别为2,3,5 为一组,n位上的0表示编号为n的队员不在这组,1则表示在本组;

重要的是如何列举出所有的分组情况://给出代码

for(int i = 1; i < p[n]; ++ i)
for(int j = i; j <= n ; ++ j)
if(i & p[j-1])
ztime[i] = max(time[j],ztime[i]), zweight[i] += w[j];

设p[n]为2的n次方,即枚举的方案组数;ztime[]是这个队伍中走最长时间的队员的时间;zweight[]是该队伍总的重量;

i & p[j-1] 即在判断第j号队员是否在i表示的组成员中,非0—在 ,0—不在。

之后再对分组进行动态规划:

for(int i = 1; i < p[n]; ++ i)
   for(int j=1,u=0;j && u!=j; j = i & (j-1) )
      if(zweight[j] <= W)
        u=i^j,dp[i] = min(dp[i], dp[u]+ztime[j]);

这里说一下:1) i&j-1 表示除了该队伍最后一个队员的新的队伍(拆分枚举)

                     2)min(dp[i],dp[u]+ztime[j])表示没组这支队伍i方案的时间,和组了这支队伍的时间(这支队伍的时间+剩下人的时间)

                       3)已经给出的是优化型,下面给出原型代码

for(int i = 1; i < p[n]; ++ i)
   for(int j=1;j ; j = i & (j-1) )
      if(zweight[j] <= W)
        dp[i] = min(dp[i], dp[i^j]+ztime[j]);

大家可以思考下有什么区别(提示:过滤掉重复的队伍)

下面给出代码:

分割线


#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1 << 16;//2的16次方,最大方案 
int dp[MAXN],zweight[MAXN],ztime[MAXN];//dp数组,方案重量,方案时间 
int main(){
	int W,n; 
	cin>>W>>n;
	int p[n+1], t[n+1], w[n+1];
	memset(p,1,sizeof(p));//p的初始化 
	for(int i = 1;i <= n; ++ i)
	cin>>t[i]>>w[i],p[i] = 1 << i;//i队员的编号位置 
	for(int i = 1; i < p[n]; ++ i)//总方案 
	   for(int j = 1; j <= n; ++ j)//总人数 
	      if(i & p[j-1])//i队员在j队伍中 
	        ztime[i] = max(t[j], ztime[i]),zweight[i] += w[j];//队伍的时间和重量 
    memset(dp,0x3f,sizeof(dp)); dp[0] = 0;//初始化dp 
	for(int i = 1; i < p[n]; ++ i)
	   for(int j = i, u = 0; j && (j != u); j = i&(j-1))//上面详细说了,这里略过 
	      if(zweight[j] <= W)
	        u=i^j,dp[i] = min(dp[i], dp[u]+ztime[j]);
	cout<<dp[p[n]-1]<<endl;
	return 0;
}

最后:

programming is the most fun you can have with your clothes on.

猜你喜欢

转载自blog.csdn.net/A_Pathfinder/article/details/81293007