1018 Public Bike Management (30分)(不长,不水)

1018 Public Bike Management (30分)

分析

求最短路的同时,要求带出的车子最少,再要求带回的车子最少
迪杰斯特拉算法是贪心算法的一种,迪杰斯特拉算法能得出最优解,要求问题满足最优子结构条件。若携带车辆数目与带回车辆数目这两个尺度加到其中的话,满足最优子结构条件,即不能保证当前步骤选择的节点满足路径最短、带出车子最少、带回车子最少的条件时,之后的步骤也满足全局最优的条件
反例如下:
10 4 4 5
6 7 5 0
0 1 1
0 2 1
1 3 1
2 3 1
3 4 1
因此,只能用迪杰斯特拉算法求出最短路径以及对应的各个前驱节点,再用深度优先遍历各个满足最短路径的解,从而得出全局最优解

代码

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int c, n, s, m, a, b, l, distTo[510], marked[510], bike[510], take_from = 999999999, take_back = 999999999;
vector<int> pre[510], o, oo;
vector<pair<int, int> >g[510];
struct node {
 int v, l;
 node() {}
 node(int vv, int ll) :v(vv), l(ll) {}
 bool operator<(node e)const {
  return l > e.l;
 }
};
void dfs(int i) {
 o.push_back(i);
 int j = 0;
 for (; j < pre[i].size(); ++j)dfs(pre[i][j]);
 if (j == 0) {
  int ff = 0, bb = 0;
  for (int k = o.size() - 2; k >= 0; --k) {
   bb += bike[o[k]];
   if (bb < 0) {
    ff -= bb;
    bb = 0;
   }
  }
  if (ff < take_from || (ff == take_from && bb < take_back)) {
   oo = o;
   take_from = ff;
   take_back = bb;
  }
 }
 o.pop_back();
}
int main() {
 scanf("%d %d %d %d", &c, &n, &s, &m);
 for (int i = 1; i <= n; ++i) {
  scanf("%d", &bike[i]);
  bike[i] -= c / 2;
 }
 for (int i = 0; i < m; ++i) {
  scanf("%d %d %d", &a, &b, &l);
  g[a].push_back(pair<int, int>(b, l));
  g[b].push_back(pair<int, int>(a, l));
 }
 priority_queue<node> q;
 q.push(node(0, 0));
 fill(distTo, distTo + 510, 999999999);
 distTo[0] = 0;
 while (!q.empty()) {
  int f = q.top().v;
  q.pop();
  if (f == s)break;
  marked[f] = 1;
  for (int i = 0; i < g[f].size(); ++i) {
   int v = g[f][i].first, l = g[f][i].second;
   if (distTo[v] > distTo[f] + l) {
    distTo[v] = distTo[f] + l;
    pre[v].clear();
    pre[v].push_back(f);
    q.push(node(v, distTo[v]));
   }
   else if (distTo[v] == distTo[f] + l)
    pre[v].push_back(f);
  }
 }
 dfs(s);
 printf("%d 0", take_from);
 for (int i = oo.size() - 2; i >= 0; --i)
  printf("->%d", oo[i]);
 printf(" %d", take_back);
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值