pat-1018
题意:
有n个共享单车停车点(编号1-n),编号0是共享单车的分发总站,求出从0到st上的最短路径上所需要发放或
收取的最少的单车的数量。
思路:
还是图论知识不牢固,今后三天多练练图论的题目。(参考文章)
首先找最短路径,然后在已知的几条最短路径上求出需要发放还是回收自行车,再求出它们的最小值。
(1)求出最短路径,可以用dij算法来求,由于路径不唯一,所以可以用邻接表记录这些路径。
(2)按照求好的最短路径更新所需的发放或者回收的自行车的数量。
反思:
(1)记录多条路径时可以用邻接表表示
(2)深搜一定要回溯。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 100100;
const int INF = 99999999;
int vis[maxn],dis[maxn],mp[550][550],wei[maxn];
vector <int> pre[550],path,tmpath;
int mineed,miback;
void dfs(int u)
{
tmpath.push_back(u);
if(u==0){
int v,i,need=0,back=0;
for(i=tmpath.size()-1;i>=0;i--){
v=tmpath[i];
if(wei[v]>0){
back+=wei[v];
}
else{
if(back>(0-wei[v])){
back+=wei[v];
}
else{
need+=((0-wei[v])-back);
back=0;
}
}
}
if(need<mineed){
mineed=need;
miback=back;
path=tmpath;
}
else if(need==mineed&&back<miback){
miback=back;
path=tmpath;
}
tmpath.pop_back();
return ;
}
for(int i=0;i<pre[u].size();i++)
dfs(pre[u][i]);
tmpath.pop_back();
}
int main(void)
{
int n,m,k,st,i,j,x,z,y,cmx;
scanf("%d%d%d%d",&cmx,&n,&st,&m);
for(i=1;i<=n;i++){
scanf("%d",&wei[i]);
wei[i]-=cmx/2;dis[i]=INF;
}
for(i=0;i<=n;i++)
for(j=0;j<=n;j++) mp[i][j]=INF;
for(i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
mp[x][y]=mp[y][x]=z;
}
memset(vis,0,sizeof(vis));
dis[0]=0;
for(i=1;i<=m;i++){
int mi=INF,pos=-1;
for(j=0;j<=n;j++)
if(vis[j]==0&&mi>dis[j]){
mi=dis[j];pos=j;
}
if(pos==-1) break;
vis[pos]=1;
for(j=0;j<=n;j++){
if(vis[j]==0&&mp[pos][j]!=INF){
if(dis[j]>dis[pos]+mp[pos][j]){
dis[j]=dis[pos]+mp[pos][j];
pre[j].clear();
pre[j].push_back(pos);
}
else if(dis[j]==dis[pos]+mp[pos][j]){
pre[j].push_back(pos);
}
}
}
}
mineed=INF,miback=INF;
tmpath.clear();
dfs(st);
printf("%d 0",mineed);
for(i=path.size()-2;i>=0;i--) printf("->%d",path[i]);
printf(" %d",miback);
return 0;
}