这道题的主要方法是Dijkstra+DFS。首先利用Dijkstra算法找出原点到目标p点的所有最短路径,然后利用dfs遍历所有的最短路径,更新send跟bring;
1.Dijkstra()算法的模板:
void dijkstra(){
memset(dist,0x3f,sizeof dist);//使所有到目标p点的距离初始化为无穷大
dist[p]=0;//p到自身的距离为0
for(int i=0;i<n;i++){
int t=-1;
for(int j=0;j<=n;j++){//找出没有遍历过且距离p点最近的点
if(!st[j]&&(t==-1||dist[j]<dist[t]))
t=j;
}
st[t]=true;//标记
for(int j=0;j<=n;j++){//更新与t相关的节点
dist[j]=min(dist[j],dist[t]+d[t][j]);
}
}
}
2.send(PBMC需要发出的自行车数量)如何在满足要求下保证最小,可以send初始为0,DFS遍历所有最短路径,当节点不完美时,send-(最大数量/2-节点bike的数量)即需要满足perfect所需的bike数目的负值。则send的值为abs(最小的负数)。而带回来的bike数量则是发出的自行车数量-路径满足perfect所需的bike数量。
同时注意DFS更新答案的优先级如下:
(1)路径取得最小值 (Dijkstra()已经实现)
(2)在(1)都满足的条件下,PBMC发出的bike需要最小
(3)在(1)(2)都满足的条件下,带回来的bike需要最小;
代码实现:
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=510;
int w[N];//每个station的bike
int d[N][N];//station之间的时间
int dist[N];//每个station到达目标station的最短路径
int cmax,n,m,p;
int send=0x3f3f3f,bring=0x3f3f3f;//send为PBMC要发出的bike,bring是带回来的bike,初始化为无穷大
bool st[N];//标记是否访问过
vector<int> ans,path;
void dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[p]=0;
for(int i=0;i<n;i++){
int t=-1;
for(int j=0;j<=n;j++){
if(!st[j]&&(t==-1||dist[j]<dist[t]))
t=j;
}
st[t]=true;
for(int j=0;j<=n;j++){
dist[j]=min(dist[j],dist[t]+d[t][j]);
}
}
}
/*(1)路径取得最小值
(2)在(1)都满足的条件下,PBMC发出的bike需要最小
(3)在(1)(2)都满足的条件下,带回来的bike需要最小;*/
void dfs(int u,int s,int mins){
if(u){
s-=cmax/2-w[u];//station变成perfect所需的bike
mins=min(s,mins);//取最小的负数
}
if (u==p)
{
int sd=abs(min(mins,0));//mins是路径上所有station变成perfect所需的bike的最小的负数,即send的负数,故send=abs(mins)若大于0,则不需要发出bike,故取0。send=abs(min(mins,0));
int bg=s+sd;
if(sd<send) ans=path,send = sd,bring = bg; //该条路径下比其他最短路径PBMC所需要发出的bike更少,即满足(2)替换答案;
else if(sd==send&&bg<bring) ans =path,bring=bg;//满足(3)的情况
return;
}
for (int i = 1; i <= n; i ++ )
if (dist[u] ==d[u][i] + dist[i])//u->i 当u到目标p点的最短距离等于u带i的距离+i到目标p点的最短距离,则i是最短路径上的节点
{
path.push_back(i);
dfs(i,s,mins);
path.pop_back();//回溯
}
}
int main()
{
cin>>cmax>>n>>p>>m;
for(int i=1;i<=n;i++) cin>>w[i];
memset(d,0x3f,sizeof d);
while(m--){
int a,b,c;
cin>>a>>b>>c;
d[a][b]=d[b][a]=min(d[a][b],c);//无向图可以看出有两条边的有向图,所以d[a][b]=d[b][a],min(d[a][b],c)是防止有重边的题目,可写可不写
}
dijkstra();
path.push_back(0);//路径的起始点0
dfs(0,0,0);//遍历所有可能的最短路径
cout<<send<<" "<<0;
for (int i=1;i<ans.size();i ++ )
cout<<"->"<<ans[i];
cout << " " <<bring << endl;
return 0;
}