【题解】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;
}

猜你喜欢

转载自www.cnblogs.com/JCNL666/p/10731266.html