P5911 [POI2004]PRZ 题解
看到
首先我们可以预处理出来每个状态的过桥时间和总重量。对于一个状态
如果发现集合
代码:
#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; }