这题就是先求最短路径,当有多条最短路径的时候按照如下原则择优:sent的自行车较少的更优,如果sent的自行车数量相同,则take back的自行车数量最少的更优。
第一次提交的时候只过了4个case,原因在于:只要前面station的自行车数量不足,就必须从PBMC派送自行车,无论后面路径上的自行车数量是否有多余,也就是说是一个不可逆转的过程。后来改写了程序,在Dijkstra算法的基础上,逐步地对sentBike和backBike进行累加,提交后第7个case不过,无奈之下只好百度,发现不能再Dijkstra的时候同时更新自行车的sentBike和backBike,因为它们不满足最优子结构性质。只能用Dijkstra算出最短距离,然后用dfs搜索最优路径。
第7个case不过的程序:
//第7个case不过,因为不满足最优子结构,不能将sentBike简单的累加
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;
const int INF = 10000000;
const int MAXV = 505;
int Cmax, N, Sp, M;
int sentBike[MAXV] = {0}, backBike[MAXV] = {0};
int d[MAXV]; //最短距离数组
int C[MAXV]; //C[i]表示第i个station的自行车数量
int path[MAXV]; //path[i]存放第i个点的前驱顶点
int G[MAXV][MAXV]; //图的邻接矩阵
bool vis[MAXV] = {false}; //标记顶点是否被访问
void Dijkstra()
{
d[0] = 0, path[0] = -1, C[0] = 0;
for(int i = 0; i <= N; i++)
{
int u = -1, MIN = INF;
for(int j = 0; j <= N; j++)
{
if(!vis[j] && d[j] < MIN)
MIN = d[u = j];
}
if( u == -1) return;
vis[u] = true;
for(int v = 0; v <= N; v++)
if(!vis[v])
{
int count = Cmax / 2 - C[v];
if(d[u] + G[u][v] == d[v])
{
if(sentBike[u] + max(0, count) < sentBike[v])
{
sentBike[v] = sentBike[u] + max(0, count); //更新sentBike[v]
path[v] = u;
}
else if(sentBike[u] + max(0, count) == sentBike[v])
{
if(backBike[u] - min(0, count) < backBike[v])
{
backBike[v] = backBike[u] - min(0, count);//更新backBike[v]
path[v] = u;
}
}
}
else if(d[u] + G[u][v] < d[v])
{
d[v] = d[u] + G[u][v];
path[v] = u;
if(count >= 0)
{
if(backBike[u] - count > 0)
{
backBike[v] = backBike[u] - count;
sentBike[v] = sentBike[u];
}
else
{
backBike[v] = 0;
sentBike[v] = sentBike[u] + count - backBike[u];
}
}
else
{
sentBike[v] = sentBike[u];
backBike[v] = backBike[u] - count;
}
}
}
}
}
void output()
{
vector<int> vi;
int u = Sp;
while(path[u] != -1)
{
vi.push_back(u);
u = path[u];
}
vi.push_back(0);
cout << sentBike[Sp] << " ";
for(int i = vi.size() - 1; i >=0; i--)
{
cout << vi[i];
if(i) cout << "->";
}
cout << " " << backBike[Sp] << endl;
}
int main()
{
//freopen("in_1018.txt", "r", stdin);
cin >> Cmax >> N >> Sp >> M;
for(int i = 1; i <= N; i++)
cin >> C[i];
for(int i = 0; i <= N; i++) //初始化邻接矩阵G
for(int j = 0; j <= N; j++)
G[i][j] = INF;
fill(d, d + MAXV, INF); //初始化距离为无穷大
int start, end, time;
for(int i = 0; i < M; i++)
{
cin >> start >> end >> time;
G[start][end] = G[end][start] = time;
}
Dijkstra();
output();
}
全部AC的程序:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;
const int INF = 10000000;
const int MAXV = 505;
int Cmax, N, Sp, M;
int sentBike = INF, backBike = INF;
int d[MAXV]; //最短距离数组
int C[MAXV]; //C[i]表示第i个station的自行车数量
int G[MAXV][MAXV]; //图的邻接矩阵
bool vis_dij[MAXV] = {false}; //标记顶点是否被访问
bool vis_dfs[MAXV] = {false};
int curTime = 0; //当前花费的时间
int curSentBike, curBackBike; //当前需要从PBMC派出去的和带回PBMC的自行车数量
vector<int> path; //符合条件的最短路径
vector<int> curPath; //dfs过程中遍历的路径
void Dijkstra()
{
d[0] = 0, C[0] = 0;
for(int i = 0; i <= N; i++)
{
int u = -1, MIN = INF;
for(int j = 0; j <= N; j++)
if(!vis_dij[j] && d[j] < MIN)
MIN = d[u = j];
if(u == -1) return;
vis_dij[u] = true;
for(int v = 0; v <= N; v++)
if(!vis_dij[v] && d[u] + G[u][v] < d[v])
d[v] = d[u] + G[u][v];
}
}
bool judge(vector<int> curPath) //按照题意选择最优的最短路径
{
curSentBike = curBackBike = 0;
for(int i = 0; i < curPath.size(); i++)
{
int v = curPath[i];
int count = Cmax / 2 - C[v];
if(count >= 0)
{
if(curBackBike - count > 0) curBackBike -= count;
else
{
curSentBike += count - curBackBike;
curBackBike = 0;
}
}
else curBackBike -= count;
}
//优先选择派出的自行车数量最少的最短路径,其次再选带回最少的最短路径
if(curSentBike != sentBike) return curSentBike < sentBike;
else return curBackBike < backBike;
}
void dfs(int cur) //深度优先搜索最短路径
{
if(cur == Sp)
{
if(curTime == d[Sp] && judge(curPath))
{
path = curPath;
sentBike = curSentBike;
backBike = curBackBike;
}
return;
}
for(int i = 1; i <= N; i++)
{
if(G[cur][i] != INF && !vis_dfs[i])
{
vis_dfs[i] = true;
curPath.push_back(i);
curTime += G[cur][i];
dfs(i);
vis_dfs[i] = false;
curPath.pop_back();
curTime -= G[cur][i];
}
}
}
void print()
{
cout << sentBike << " 0";
for(int i = 0; i < path.size(); i++)
cout << "->" << path[i] ;
cout << " " << backBike << endl;
}
int main()
{
//freopen("in_1018.txt", "r", stdin);
cin >> Cmax >> N >> Sp >> M;
for(int i = 1; i <= N; i++)
cin >> C[i];
for(int i = 0; i <= N; i++) //初始化邻接矩阵G
for(int j = 0; j <= N; j++)
G[i][j] = INF;
fill(d, d + MAXV, INF); //初始化距离为无穷大
int start, end, time;
for(int i = 0; i < M; i++)
{
cin >> start >> end >> time;
G[start][end] = G[end][start] = time;
}
Dijkstra();
dfs(0);
print();
}