HDU - 3339 In Action(dijkstra+01背包)

看题目戳我

题目大意:

       有n个发电站,m条路,每条路有各自的距离,每个发电站有各自的发电量,现在需要炸毁它们,一辆坦克只能炸毁一个发电站,而且需要炸毁的发电厂的发电量需要大于所有发电站所产生的总电量的一半,求坦克走的最短距离。

题目思路:

      看完这个题目一个比较容易产生的想法就是:求出源点到达其他点的最短距离,然后把距离从小到大排队,看到达哪个点(即哪个路线)炸毁的发电量可以达到要求。

      下面比较明显的就是,想要求出源点到达每个其他点的距离,dijkstra当然是首选。

      接下来就是如何判断这条路径能不能达到要求。

      我们可以抽象出来(好吧也并不是很抽象),思路反一下,走这么长的距离最多可以炸毁多少发电量。这样是不是有点眼熟了呢?——跟背包问题有点像。把到每个点走的路长当作背包的体积,炸毁的发电量是每次可以装进去的价值。然后,bingo!

其他细节见代码

题目代码:

##include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
#define maxn 10005
#define INF 0x3f3f3f3f

using namespace std;
int dis[105];
int f[80050];//dp用的
struct Edge
{
     int u,v,w;
     Edge(int uu,int vv,int ww):u(uu),v(vv),w(ww){}
};
struct Node
{
     int id;
     int w;
     bool operator<(const Node &b)
          const{w>b.w;}
}mid;
struct P
{
     int po;
     int d;
}poww[105];
vector<Edge>e[maxn];
priority_queue<Node>pq;

int cmp(P a,P b)
{
     return a.d<b.d;
}
void dijk(int s)//dijkstra模板求出最短路
{
     pq.push(Node{s,0});
     dis[s]=0;
     while(!pq.empty())
     {
          mid=pq.top();
          pq.pop();
          int card=mid.id;
          if(mid.w!=dis[card])
               continue;
          for(int i=0;i<e[card].size();i++)
          {
               //printf("%d---%d----%d\n",card,dis[card],e[card][i].v);
               if(dis[e[card][i].v]>dis[card]+e[card][i].w)
               {
                    dis[e[card][i].v]=dis[card]+e[card][i].w;
                    pq.push(Node{e[card][i].v,dis[e[card][i].v]});
                    //printf("%d-----------------------%d\n",dis[card],e[card][i].w);
               }
          }
     }
}
int main(void)
{
     int t;
     int n,m;
     int a,b,c;
     double tol;
     scanf("%d",&t);
     while(t--)
     {
          //cout<<0x3f3f3f3f<<endl;
          scanf("%d%d",&n,&m);
          memset(dis,0x3f,sizeof(dis));//初始化请注意
          memset(f,0,sizeof(f));
          memset(poww,0,sizeof(poww));
          for(int i=0;i<=n;i++)
               e[i].clear();
          //
          for(int i=0;i<m;i++)
          {
               scanf("%d%d%d",&a,&b,&c);
               e[a].push_back(Edge{a,b,c});
               e[b].push_back(Edge{b,a,c});
          }
          dijk(0);
          //以上求出最短路
          //print(n);
          int sum=0;
          int oil=0,p=0;
          for(int i=1;i<=n;i++)
          {
               scanf("%d",&poww[i].po);//价值
               sum+=poww[i].po;
               if(dis[i]<INF)
               {
                    oil+=dis[i];
                    p++;
               }
               poww[i].d=dis[i];//体积
          }
          //print(n);
          sort(poww+1,poww+n+1,cmp);
          //可用油量为j的时候可以获得多少能量
          for(int i=1;i<=p;i++)
          {
               for(int j=oil;j>=poww[i].d;j--)//注意如何把各个发电站的“体积”和“价值”对应起来,用P结构体
               {
                    f[j]=max(f[j],f[j-poww[i].d]+poww[i].po);//依次获得相应油量下可以有多少价值
               }
          }
          int i;
          for(i=0;i<=oil;i++)
          {
               if(f[i]>=(sum/2+1))
                    break;
          }
          if(i<=oil)
               printf("%d\n",i);
          else
               printf("impossible\n");
     }
     return 0;
}
/*
2
5 7
0 2 6
0 1 4
0 1 2
2 3 3
3 4 1
3 5 6
4 5 7
6 12 4 3 2
*/

呼呼

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值