P5911 [POI2004]PRZ 题解

题目链接

看到 n 很小,想到状压dp。

首先我们可以预处理出来每个状态的过桥时间和总重量。对于一个状态 s,枚举它的子集 p ,令 qps 中的补集,有 dps=min(dpp+dpq)

如果发现集合 s 的总重量小于桥的限制,将它初始化为该状态的过桥时间即可;否则,赋值正无穷。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 70000;
inline int read(){
int x = 0; char ch = getchar();
while(ch<'0' || ch>'9'){
ch = getchar();
}
while(ch>='0'&&ch<='9'){
x = x*10+ch-48;
ch = getchar();
}
return x;
}
int mxw, n;
int t[20], w[20];
int dp[N];
int tim[N], sum[N];
int main(){
mxw = read(), n = read();
for(int i = 0; i<n; i++){
t[i] = read(), w[i] = read();
}
for(int i = 1; i<=(1<<n)-1; i++){
for(int j = 0; j<n; j++){
if((i>>j)&1){
tim[i] = max(t[j], tim[i]);
sum[i]+= w[j];//预处理每个集合对应的重量和过桥时间。
}
}
}
memset(dp, 0x3f, sizeof(dp));
dp[0] = 0;
for(int i = 1; i<=(1<<n)-1; i++){
if(sum[i]<=mxw) {
dp[i] = tim[i];//如果能过,则最优时间一定为这个集合所有人过桥的时间。
} else {
for(int s = i; s; s = (s-1)&i) {
int ss = i^s;
dp[i] = min(dp[s]+dp[ss], dp[i]);//拆成若干个集合的和。
}
}
}
printf("%d\n", dp[(1<<n)-1]);
return 0;
}
posted @   霜木_Atomic  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示