【题解】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;
}
posted @ 2019-04-18 18:00  章鱼那个哥  阅读(156)  评论(0编辑  收藏  举报