HDU-3339 In Action(最短路径+01背包)

题意

给定一个无向图代表一个电网 n n 个节点 m 条边,每个节点上都有一个电站,每个电站都有一个功率,每条边上都有一个价值。现在在节点 0 0 上(不属于那 n 各节点),有无数辆坦克可以开到一个电站并将它关闭(关闭后坦克不能移动)。求关闭一半以上的功率至少需要多少价值。
1n100 1 ≤ n ≤ 100
1m10000 1 ≤ m ≤ 10000

思路

最短路径与01背包的结合,将从 0 0 节点到其他节点的最短路长度看作物品的体积,将每个电站的功率看作它的价值。跑一遍 01背包再扫一遍 dp 数组找到最优解即可。

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
using namespace std;

struct Pack
{
    int V;
    int dp[10003];
    Pack(int _){V=_;memset(dp,0,sizeof(dp));}
    void ZeroOne_load(int v,int p)
    {
        DOR(i,V,v)dp[i]=max(dp[i],dp[i-v]+p);
        return;
    }
};
struct node
{
    int at,path;
    bool operator<(const node &_)const
    {
        return path>_.path;
    }
};
struct edge
{
    int to,cost;
};
struct dijkstra
{
    int dis[103],n;
    vector<edge>E[103];
    dijkstra(int _)
    {
        n=_;
        memset(dis,63,sizeof(dis));
        FOR(i,1,n)E[i].clear();
    } 
    void add(int u,int v,int w)
    {
        E[u].push_back((edge){v,w});
        return;
    }
    void solve(int s)
    {
        dis[s]=0;
        priority_queue<node>q;
        while(!q.empty())q.pop();
        q.push((node){s,0});
        while(!q.empty())
        {
            node now=q.top();q.pop();
            int u=now.at;
            if(dis[u]<now.path)continue;
            FOR(i,0,(int)E[u].size()-1)
            {
                int v=E[u][i].to,w=E[u][i].cost;
                if(dis[u]+w<dis[v])
                {
                    dis[v]=dis[u]+w;
                    q.push((node){v,dis[v]}); 
                }
            }
        }
        return;
    }
    int go(int v){return dis[v];}
};

int main()
{
    int T,n,m;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        dijkstra SP(n);
        FOR(i,1,m)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            SP.add(u,v,w);SP.add(v,u,w);
        }
        SP.solve(0);
        Pack P(10000);
        int tot=0;
        FOR(i,1,n)
        {
            int c;
            scanf("%d",&c);
            tot+=c;
            P.ZeroOne_load(SP.go(i),c);
        }
        bool flag=0;
        FOR(i,0,P.V)
        {
            if(P.dp[i]>tot/2)
            {
                printf("%d\n",i);
                flag=1;
                break;
            }
        }
        if(!flag)printf("impossible\n"); 
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值