套路跟前一题完全一样,只是要计算需要送出和收回的车。其中两个数据卡的是一条路中后面如果有多余的车是不能填充前面站点缺少的车的,所以在dfs中用了两个变量来分别记录需要的车和多余的车。
这两题刻意留到数据结构复习完图之后写,加深下体会。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<climits>
#include<vector>
#include<cstring>
using namespace std;
int c,n,s,m,half;
const int INF = 100000005;
int graph[505][505];
int bike[505];
int dis[505];
int vis[505];
int findMinDis(){
int min_dis = INF, v = 0;
for(int i = 1; i <= n; ++i){
if(min_dis > dis[i] && !vis[i]){
min_dis = dis[i];
v = i;
}
}
return v;
}
void Dijkstra(){
for(int i = 0; i <= n; ++i){
dis[i] = graph[0][i];
vis[i] = 0;
}
vis[0] = 1;
int v;
while(1){
v = findMinDis();
if(!v) break;
vis[v] = 1;
for(int i = 1; i <= n; ++i){
if(!vis[i] && dis[v] + graph[v][i] < dis[i]){
dis[i] = dis[v] + graph[v][i];
}
}
}
}
vector<int> ans_path;
int min_send = INF, min_back = INF;
void dfs(int pos, int time, int need, int left, vector<int> path){
if(time > dis[s]) return;
if(pos == s){
if(need < min_send){
min_send = need;
min_back = left;
ans_path = path;
}
else if(need == min_send){
if(left < min_back){
min_back = left;
ans_path = path;
}
}
}
for(int i = 1; i <= n; ++i){
if(!vis[i] && graph[pos][i] < INF){
vis[i] = 1;
path.push_back(i);
int tmp = bike[i]-half;
if(tmp >= 0){//remain bikes
dfs(i,time+graph[pos][i],need,left+tmp,path);
}
else{
if(left > 0 && left >= -tmp){
dfs(i,time+graph[pos][i],need,left+tmp,path);
}
else if(left >= 0 && left < -tmp){
dfs(i,time+graph[pos][i],need-tmp-left,0,path);
}
}
path.pop_back();
vis[i] = 0;
}
}
}
int main(){
scanf("%d%d%d%d",&c,&n,&s,&m);
half = c/2;
for(int i = 0; i <= n; ++i){
if(i > 0) scanf("%d",&bike[i]);
for(int j = 0; j <= n; ++j){
graph[i][j] = INF;
if(i == j) graph[i][j] = 0;
}
}
int a, b, t;
for(int i = 0; i < m; ++i){
scanf("%d%d%d",&a,&b,&t);
graph[a][b] = graph[b][a] = t;
}
Dijkstra();
vector<int> tmp;
memset(vis,0,sizeof(vis));
dfs(0,0,0,0,tmp);
printf("%d 0",min_send);
for(int i = 0; i < ans_path.size(); ++i){
printf("->%d",ans_path[i]);
}
printf(" %d",min_back);
return 0;
}