洛谷:P5911 [POI2004]PRZ

标题:状压dp

题目背景
一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥。
题目描述
桥已经很旧了, 所以它不能承受太重的东西。任何时候队伍在桥上的人都不能超过一定的限制。 所以这只队伍过桥时只能分批过,当一组全部过去时,下一组才能接着过。队伍里每个人过桥都需要特定的时间,当一批队员过桥时时间应该算走得最慢的那一个,每个人也有特定的重量,我们想知道如何分批过桥能使总时间最少。
输入格式
第一行两个数: WWW 表示桥能承受的最大重量和 nnn 表示队员总数。
接下来 nnn 行:每行两个数: ttt 表示该队员过桥所需时间和 www 表示该队员的重量。
输出格式
输出一个数表示最少的过桥时间。
输入输出样例
输入 #1

100 3
24 60
10 40
18 50

输出#1

42

思路:
枚举子集的模板题
dp表示最短时间
dt代表花费的时间
dw代表重量
通过枚举不同的状态,用二进制表示,其中1代表已过的,0代表还没过
然后类似与背包问题,过还是不过(装还是不装这个物品),具体看代码
代码:

#include
using namespace std;
typedef long long int ll;
int W,n;
string a;
string judge(int x)
{
 a.clear();
 while(x)
 {
  a+=x%2+'0';
  x/=2;
 }
 reverse(a.begin(),a.end());
 return a;
}//只是用来查看二进制,没有影响
int main()
{
 cin>>W>>n;
 vector<int> t(n),w(n);
 for(int i=0;i<n;i++)
 {
  cin>>t[i]>>w[i];
 }
 vector<int> dt(1<<n),dw(1<<n);
 for(int i=0;i<(1<<n);i++)//遍历所有情况 
 {
  for(int j=0;j<n;j++)
  {
   if(i&(1<<j))continue;//已经访问过
   dt[i|(1<<j)]=max(dt[i],t[j]);//走得最慢的呢个
   dw[i|(1<<j)]=dw[i]+w[j];//重量之和 
  }
 }
 /*
  i&(1<
 vector<int> dp(1<<n,999);//初始化为999
 dp[0]=0;
 for(int i=1;i<(1<<n);i++)//遍历所有情况 
 {
  for(int j=i;j;j=(j-1)&i)/*根据j二进制中1的位数,进行遍历(遍历所有二进制中1的位数少于i的)*/
  {
   if(dw[j]<=W)dp[i]=min(dp[i],dt[j]+dp[i^j]);//j+i^j=i,相当于dp[i]=min(dp[i],dp[i-j]+dt[j]);
  }
  cout<<endl;
  } 
  cout<<dp[(1<<n)-1]<<endl;
  /*
  类似与背包问题
  */
 return 0;
}

你可能感兴趣的:(动态规划)