【题解】2073: [POI2004]PRZ
\(Description:\)
有一群人要过一个有承重限制,只能一批一批的走这个桥,每个人有一个过桥时间和重量
\(Sample\) \(Input:\)
100 3
24 60
10 40
18 50
\(Sample\) \(Output:\)
42
\(Solution:\)
发现这题好像数据范围不大,那么大概是暴力吧?
然而事实证明是状压dp。
那么考虑把集合用二进制存下,设我们现在做到集合 \(s\)。
那么 \(s\) 肯定可以从他的子集那儿转移过来。 那些 \(s\) 中为 \(1\) 而 \(t\) (s的子集) 不为 \(1\) 的人 就是这一批过桥的人。
那么预处理这些人的总重量 \(load[t]\) 和过桥时间 \(Time[t]\)。
转移:
\(f[s]=min_{t\ \subseteq\ s }(f[s],f[t]+Time[s\ \ xor \ t])\)
害怕,这居然是我第一次一遍 A 的dp题。
开心~~
#include<bits/stdc++.h>
using namespace std;
int Max_load,n,Max_status;
const int N=16,M=(1<<(N+1))+5;
int f[M],t[N],l[N],Time[M],load[M];
inline int lowbit(int x){
return x&(-x);
}
int main(){
scanf("%d%d",&Max_load,&n);
for(int i=1;i<=n;++i) scanf("%d%d",&t[i],&l[i]);
Max_status=(1<<n)-1;
for(int i=0;i<=Max_status;++i){
for(int j=1;(1<<(j-1))<=i;++j) if(i&(1<<(j-1))){
Time[i]= max(Time[i],t[j]);
load[i]+=l[j];
}
}
memset(f,0x3f,sizeof(f));
f[0]=0;
for(int i=0;i<=Max_status;++i){
for(int j=i;j>=0;j=(j-1)&i){
if(load[i^j]<=Max_load)
f[i]=min(f[i],f[j]+Time[i^j]);
if(!j) break;
}
}
printf("%d\n",f[Max_status]);
return 0;
}