求單源最短路,而且要求輸出路徑,非常完美的Dijkstra問題。
用Dijkstra求出多條路徑,再用DFS找到符合要求的路徑。(題目保證有唯一解)
一開始樣例5和7過不了,是因爲忽略了一個條件:後面的多餘的車子不能補充前面的。
我原來的算法是直接統計一條路上放出多少,收回多少直接抵消掉,這種算法就會導致後面的車子補充前面車子的情況出現。例如每個車站上限2量,現在路徑上車的數量是0→2,這種情況應該send一輛back一輛,而不是send零back零。
就因爲這一點思路上的不一樣,代碼就要大面積改動。。以後要仔細審題啊!
AC代碼:
//1018 dijkstra+dfs
int c,n,idx,m;
int station[505],road[505][505],v[505],d[505],minfa[505],maxfa[505],nowfa[505];
//保存重複路徑
vector<int> fa[505];
vector<int> pathh;
vector<int> ans;
//send表示要借出的車子,如果當前車站車子不夠先看手裏頭已經回收的車子夠不夠,不夠就只能從中心拿,不能取後面的
//backk表示回收的車子
int send,backk,minsend = 50010,minbackk = 50010;
void copy_s(){
ans.clear();
for(int i=0;i<pathh.size();i++)
ans.push_back(pathh[i]);
}
//借車收車的路徑要正着計算
//但是保存的幾個最短路徑是倒着保存的,所以要藉助棧把順序正過來
//這裏用vector實現棧的功能,因爲複製函數比stack好寫。。。
void dfs(int i){
if(i == 0){
send=0,backk=0;
for(int p=pathh.size()-1;p>=0;--p){
if(station[pathh[p]] - c/2 >= 0) backk += (station[pathh[p]] - c/2);
else{
if(backk >= c/2-station[pathh[p]]) backk -=(c/2-station[pathh[p]]);
else if(backk>0 && backk < (c/2 - station[pathh[p]]) ) {send += (c/2 - station[pathh[p]]-backk);backk = 0;}
else if(backk == 0) send += (c/2 - station[pathh[p]]);
}
}
//感覺下面這個判斷不是很嚴謹,但是題目保證了一定能有唯一解,所以能AC
if(send<minsend){minsend = send;minbackk = backk;copy_s();}
else if(send == minsend) {
if(backk<minbackk) {minsend = send;minbackk = backk;copy_s();}
}
return;
}
for(int j=0;j<fa[i].size();j++){
pathh.push_back(i);
dfs(fa[i][j]);
pathh.pop_back();
}
}
void dijkstra(){
//找到最短路徑
memset(v,0,sizeof(v));
for(int i=0;i<=n;i++) d[i] = (i==0 ? 0:INT_MAX);
for(int i=0;i<=n;i++){
int x,m = INT_MAX;
//找到沒去過且距離最短的路
for(int y=0;y<=n;y++) if(!v[y]&&d[y]<=m) m = d[x=y];
v[x] = 1;
//對於x出發的邊(x,y),更新d[y]
for(int y=0;y<=n;y++) if(road[x][y]>0 && (d[y]>d[x]+road[x][y])){
d[y] = d[x] + road[x][y];
fa[y].clear();
fa[y].push_back(x);
}else if(road[x][y]>0 && (d[y]==d[x]+road[x][y])){
//如果有到y點的重複路徑,添加前置結點
fa[y].push_back(x);
}
}
dfs(idx);
printf("%d 0",minsend);
for(int i=ans.size()-1;i>=0;--i) printf("->%d",ans[i]);
printf(" %d",minbackk);
}
int main(){
int x,y,z;
scanf("%d%d%d%d",&c,&n,&idx,&m);
memset(station,0,sizeof(station));
memset(road,-1,sizeof(road));
for(int i=1;i<=n;i++)
scanf("%d",station+i);
while(m--){
scanf("%d%d%d",&x,&y,&z);
road[x][y] = road[y][x] = z;
}
dijkstra();
return 0;
}