原题:
题目大意:每个自行车车站的最大容量为一个偶数cmax,如果一个车站里面自行车的数量恰好为cmax / 2,那么称处于完美状态。如果一个车站容量是满的或者空的,控制中心(处于结点0处)就会携带或者从路上收集一定数量的自行车前往该车站,一路上会让所有的车站沿途都达到完美。现在给出cmax,车站的数量n,问题车站sp,m条边,还有距离,求最短路径。如果最短路径有多个,求能带的最少的自行车数目的那条。如果还是有很多条不同的路,那么就找一个从车站带回的自行车数目最少的(带回的时候是不调整的)~
分析:Dijkstra + DFS。如果只有Dijkstra是不可以的,因为minNeed和minBack在路径上的传递不满足最优子结构,不是简单的相加的过程,只有在所有路径都确定了之后才能区选择最小的need和最小的back
只有Dijkstra(两个点无法通过)
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include<stack>
#include<queue>
#include<sstream>
using namespace std;
/*
A1018 Public Bike Management (30 分)
这题由于回来时不会放车,所以不是求全局最优解,不能用Dijstra
*/
const int MaxN = 510;
const int Inf = 0x3fffffff;
int G[MaxN][MaxN]; //边
int V[MaxN] = { 0 }; //点权,每个点的自行车数
int N; //the total number of stations. But you need to add PBMC which is named "0"
int Cmax; // the maximum capacity of each station,
int Sp; //the index of the problem station
int M; //the number of roads
//找以s为起点的最短路,返回s->e最短路的编号序列
vector<int> Dijkstra(int s, int e, vector<int> &bike) {
vector<int> path(N + 1, -1); //存储路线
vector<bool>vis(N + 1);
vector<int> tim(N + 1);
fill(vis.begin(), vis.end(), false);
fill(tim.begin(), tim.end(), Inf);
fill(bike.begin(), bike.end(), 0); //存储一路可以获得车子数,负数代表需要补充
tim[s] = 0;
for (int i = 0; i < N+1; i++) {
//寻找tim[]最小的未访问的结点v
int v = -1, MIN = Inf;
for (int j = 0; j < N + 1; j++) {
if (tim[j] < MIN && vis[j]==false)
{
v = j;
MIN = tim[j];
}
}
if (v == -1) {
cout << "Not a connected Graph!\n";
break;
}
//访问
vis[v] = true;
//以结点v为中继更新未访问结点tim[]和path[]
for (int j = 0; j < N + 1; j++) {
if (vis[j] == false && G[v][j] != Inf) {
if (tim[j] > tim[v] + G[v][j]) {
tim[j] = tim[v] + G[v][j];
path[j] = v;
bike[j] = bike[v] + V[j] - Cmax / 2;
}
else if (tim[j] == tim[v] + G[v][j] ) {
//时间相等,1、比较送出车子数;2、比较运回车子数
if (abs(bike[j]) > abs(bike[v] + V[j] - Cmax / 2)) {
path[j] = v;
bike[j] = bike[v] + V[j] - Cmax / 2;
}
}
}
}
}
//s->e最短路的编号序列
vector <int> S_path;
stack<int> st;
int poi = e;
while (poi != -1) {
st.push(poi);
poi = path[poi];
}
while (!st.empty()) {
S_path.push_back(st.top());
st.pop();
}
return S_path;
}
int main() {
//freopen("input.txt", "r", stdin);
fill(G[0], G[0] + MaxN * MaxN, Inf);
G[0][0] = 0;
cin >> Cmax >> N >> Sp >> M;
for (int i = 1; i <= N; i++)
cin >> V[i];
for (int i = 0; i < M; i++) {
int a, b, t;
cin >> a >> b >> t;
G[a][b] = G[b][a] = t;
}
vector<int> bike(N + 1),S_path; //bike存储一路可以获得车子数,负数代表需要补充
S_path=Dijkstra(0, Sp, bike);
//Output
if (bike[Sp] >= 0) {
cout << "0 0";
for (int i = 1; i < S_path.size(); i++) {
cout << "->" << S_path[i];
}
cout << " " << bike[Sp] << endl;
}
else {
cout << abs(bike[Sp]) << " 0";
for (int i = 1; i < S_path.size(); i++) {
cout << "->" << S_path[i];
}
cout << " " << 0 << endl;
}
return 0;
}
DFS
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int inf = 99999999;
int cmax, n, sp, m;
int minNeed = inf, minBack = inf;
int e[510][510], dis[510], weight[510];
bool visit[510];
//pre[i]记录到i的所有最短时间的路径中,每一个的上一个结点
vector<int> pre[510], path, temppath;
void dfs(int v) {
temppath.push_back(v);
if (v == 0) { //从Sp回到0
int need = 0, back = 0;
for (int i = temppath.size() - 1; i >= 0; i--) {
int id = temppath[i];
if (weight[id] > 0) {
back += weight[id];
}
else {
if (back > (0 - weight[id])) {
back += weight[id];
}
else {
need += ((0 - weight[id]) - back);
back = 0;
}
}
}
if (need < minNeed) {
minNeed = need;
minBack = back;
path = temppath;
}
else if (need == minNeed && back < minBack) {
minBack = back;
path = temppath;
}
temppath.pop_back();
return;
}
for (int i = 0; i < pre[v].size(); i++)
dfs(pre[v][i]);
temppath.pop_back();
}
int main() {
fill(e[0], e[0] + 510 * 510, inf);
fill(dis, dis + 510, inf);
scanf("%d%d%d%d", &cmax, &n, &sp, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &weight[i]);
weight[i] = weight[i] - cmax / 2;
}
for (int i = 0; i < m; i++) {
int a, b;
scanf("%d%d", &a, &b);
scanf("%d", &e[a][b]);
e[b][a] = e[a][b];
}
//类似Dijkstra
dis[0] = 0;
for (int i = 0; i <= n; i++) {
int u = -1, minn = inf;
for (int j = 0; j <= n; j++) {
if (visit[j] == false && dis[j] < minn) {
u = j;
minn = dis[j];
}
}
if (u == -1) break;
visit[u] = true;
for (int v = 0; v <= n; v++) {
if (visit[v] == false && e[u][v] != inf) {
if (dis[v] > dis[u] + e[u][v]) {
dis[v] = dis[u] + e[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if (dis[v] == dis[u] + e[u][v]) {
pre[v].push_back(u);
}
}
}
}
dfs(sp);
printf("%d 0", minNeed);
for (int i = path.size() - 2; i >= 0; i--)
printf("->%d", path[i]);
printf(" %d", minBack);
return 0;
}