BZOJ2073 过桥

 BZOJ2073 过桥

一只队伍在爬山时碰到了雪崩 , 他们在逃跑时遇到了一座桥 , 他们要尽快的过桥 . 桥已经 很旧了 , 所以它不能承受太重的东西 . 任何时候队伍在桥上的人都不能超过一定的限 制 . 所以这只队伍过桥时只能分批过 , 当一组全部过去时 , 下一组才能接着过 . 队伍里每个 人过桥都需要特定的时间 , 当一批队员过桥时时间应该算走得最慢的那一个 , 每个人也有 特定的重量 , 我们想知道如何分批过桥能使总时间最少 .
 Input
 第一行两个数 : w —— 桥能承受的最大重量 (100 <= w <= 400) 和 n —— 队员总数 (1 <= n <= 16). 接下来 n 行每行两个数分别表示 : t – 该队员过桥所需时间 (1 <= t <= 50) 和 w – 该队员的重量 (10 <= w <= 100).
 Output
 输出一个数表示最少的过桥时间 .
 Sample Input
100 3
 24 60
 10 40
 18 50


 Sample Output
42


 为参与的队员进行编号:1,2,3,4....用二进制进行表示,0为存在此队员,1为不存在。例如:10010代表 2,5在队伍中,1,3,4不在。为每个队员创建三个数组,p,w,t分别为编号,体重,过桥时间。

因为可以产生的排列小于2^n(n是队员的人数),遍历所有1~2^n的数,将其中出现的队员的体重时间存入相应的数组。

再次遍历,这次应该就是动态规划了,根据前面排列的时间推出后面排列的时间,例如 00001 与 00010 推出 00011,00011为00001 + 00010 和 00011 之中的最小值。

#include<bits/stdc++.h>
using namespace std;
const int sz = 1 << 16;
int main(){
    int n,m,time[sz],weight[sz],dp[sz];
    cin >> n >> m;
    int p[n+1] = {1},t[m+1],w[m+1];
    for(int i = 1; i <= m; i++){
        cin >> t[i] >> w[i];
        p[i] = i << 1;
    }
    for(int i = 1; i < p[m]; i++){//遍历所有可能的排列
        for(int j = 1; j <= m; j++){
            if(p[j-1]&i)//当前排列中有 p[j-1] 更新time[i].weight[i]
            {
                time[i] = max(time[i],t[j]);
                weight[i] += w[j];
            }
        }
    }
    for(int i = 1; i < p[m]; i++){//遍历所有排列
        dp[i] = 2e7;//设置为最大
        for(int j = i; j; j = i&(j-1)){//从排列中依次去除一位,当满足条件时,更新
            if(weight[j] <= n){//更新内容为:dp[i] = dp[i] 与 排列中剩下的时间 + 去掉的元素时间 中最小值
                dp[i] = min(dp[i],dp[i^j]+time[j]);
            }
        }
    }
    cout<<dp[p[m]-1]<<endl;
}

猜你喜欢

转载自blog.csdn.net/WZSRLGLLLL/article/details/81105072