hdu 3339:In Action

T组数据。有足够坦克在0点,现有P个据点,Q条双向路,每条路有长度,坦克开单位长度的路需要油1升,每个据点提供一定电力。现需要占领一半以上的电力,坦克停留在一个据点即占领该据点并获得相应的电力。问最少需要多少油。

 

Spfa求0到各个据点的最短路,之后以长度为背包容量,以电力为物品价值,做01背包。注意有重边,这坑了几次。


#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;

const int inf = 1 << 20 ;
const int MAX = 105 ;
int n , m , sum ;
int map[MAX][MAX] = {0} ;
int dis[MAX] = {0} ;
int ele[MAX] = {0} ;
int dp[10005] = {0} ;
bool had[MAX] = {0} ;
queue <int> q ;

int Max(int x , int y) {
    return (x > y)? x : y ;
}

void init() {
    sum = 0 ;
    memset(had , 0 , sizeof(had)) ;
    memset(dp , 0 , sizeof(dp)) ;
    for (int i = 0 ; i <= n ; i ++) {
        for (int j = i + 1 ; j <= n ; j ++) {
            map[i][j] = map[j][i] = inf ;
        }
    }
}

void spfa() {
    dis[0] = 0 ;
    for (int i = 1 ; i <= n ; i ++) {
        dis[i] = inf ;
    }
    q.push(0) ; had[0] = 1 ;
    while (!q.empty()) {
        int t = q.front() ; q.pop() ;
        had[t] = 0 ;
        for (int i = 1 ; i <= n ; i ++) {
            if (dis[i] > dis[t] + map[t][i]) {
                dis[i] = dis[t] + map[t][i] ;
                if (!had[i]) {
                    had[i] = 1 ;
                    q.push(i) ;
                }
            }
        }
    }
}

void DP() {
    for (int i = 1 ; i <= n ; i ++) {
        if (dis[i] != inf) {
            sum += dis[i] ;
        }
    }
    for (int i = 1 ; i <= n ; i ++) {
        for (int v = sum ; v >= dis[i] ; v --) {
            if (v >= dis[i]) {
                dp[v] = Max(dp[v] , dp[v-dis[i]] + ele[i]) ;
            }
        }
    }
}

int  main() {
    //freopen("in.txt" , "r" , stdin) ;
    int T ;
    cin >> T ;
    while (T --) {
        cin >> n >> m ;
        init() ;
        while (m --) {
            int st , ed , d ;
            cin >> st >> ed >> d ;
            if (d < map[st][ed]) {
                map[st][ed] = map[ed][st] = d ;
            }
        }
        spfa() ;
        int all = 0 ;
        for (int i = 1 ; i <= n ; i ++) {
            cin >> ele[i] ;
            all += ele[i] ;
        }
        DP() ;
        int ans = -1 , half = all >> 1 ;
        for (int i = 0 ; i <= sum ; i ++) {
            //printf("%d,%d\n",i,dp[i]);
            if (dp[i] > half) {
                ans = i ;
                break ;
            }
        }
        if (ans == -1) printf("impossible\n") ;
        else cout << ans << endl ;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值