原题:1018. Public Bike Management (30)
解题思路:
1.题目是最小路径问题,采用Dijkstra算法。
2.题目中路径的判优条件十分复杂,于是改变思路,先求出所有距离相同的路径,再通过DFS算法遍历所有可能路径,求出最优路径。
DFS中判优流程如下:
将车站分为三类:(1)车子多于当前要求,将多于的车子加入remain;(2)车子少于当前要求,并且少的数量小于等于remain的数量,则在remain中减去少的数量;(3)车子少于当前的要求,且大于remain中的数量,将remain置零,并将不够的量加入take。
注:remain为模拟该路径时到达某一车站保有的车辆,take为需要从总站带的车辆。
C++代码如下:
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 510;
const int INF = 0x3fffffff;
int G[maxn][maxn];
int vis[maxn];
int bikeNum[maxn];
int d[maxn];
vector<int> pre[maxn]; //pre[i]存储i点每个可能的前驱
int n, m, c, des;
void Dijkstra(int st)
{
fill(d, d + maxn, INF);
fill(vis, vis + maxn, 0);
d[st] = 0;
for(int i = 0; i <= n; i++)
{
int u = -1, MIN = INF;
for(int j = 0; j <= n; j++)
{
if(vis[j] == 0 && d[j] < MIN)
{
u = j;
MIN = d[j];
}
}
if(u == -1) return ;
vis[u] = 1;
for(int j = 0; j <= n; j++)
{
if(G[u][j] != INF && vis[j] == 0)
{
if(d[j] > d[u] + G[u][j])
{
d[j] = d[u] + G[u][j];
pre[j].clear();
pre[j].push_back(u);
}
else if(d[j] == d[u] + G[u][j])
{
//路径长度相等时,也存入可能路径
pre[j].push_back(u);
}
}
}
}
}
int minRemain, minTake; //保存最小携带车辆,最小带回车辆
vector<int> ans, temp; //保存最终结果和临时结果
//遍历所有路径
void DFS(int des)
{
if(des == 0)
{
//当遍历到0时, 说明temp中保存了一条0到目的地的路径
//对该路径进行判优
temp.push_back(des);
int remain = 0, take = 0;
for(int i = temp.size() - 2; i >= 0; i--)
{
//要从0开始模拟
int id = temp[i];
//当当前车站的车子多于要求的数量时
if(bikeNum[id] >= c / 2)
{
remain += bikeNum[id] - c / 2;
}
else
{//少于时
if(remain > c / 2 - bikeNum[id])
{
//走到当前节点时携带的车辆比需求的多时
remain -= c / 2 - bikeNum[id];
}
else
{
//走到当前节点时携带的车辆比需求的少时
take += ((c / 2 - bikeNum[id]) - remain);
remain = 0;
}
}
}
if(take < minTake)
{
//需要携带的车辆更少
minTake = take;
minRemain = remain;
ans = temp;
}
else if(take == minTake && remain < minRemain)
{
//需要带回的车辆更少
minRemain = remain;
ans = temp;
}
temp.pop_back(); //弹出末尾节点再返回
return ;
}
temp.push_back(des); //加入当前节点
for(int i = 0; i < pre[des].size(); i++)
{
//遍历当前节点的可能前驱
DFS(pre[des][i]);
}
//弹出当前节点
temp.pop_back();
}
int main()
{
while(scanf("%d%d%d%d", &c, &n, &des, &m) != EOF)
{
for(int i = 0; i <= n; i++)
for(int j = 0; j <= n; j++)
G[i][j] = INF;
//bikeNum[0] = 0;
for(int i = 1; i <= n; i++)
scanf("%d", &bikeNum[i]);
for(int i = 0; i < m; i++)
{
int a, b, dis;
scanf("%d%d%d", &a, &b, &dis);
G[a][b] = dis;
G[b][a] = dis;
}
Dijkstra(0);
int v = des;
minRemain = INF;
minTake = INF;
DFS(des);
printf("%d ", minTake);
for(int i = ans.size() - 1 ; i >= 0; i--)
{
if(i == ans.size() - 1)
printf("%d", ans[i]);
else
printf("->%d", ans[i]);
}
printf(" %d\n", minRemain);
}
return 0;
}