本题要注意的几个点:
①选择路径的优先级:
更短路径 > 更少发车数 > 更少回收车数
②发车与回收车辆的模式:
到一个站点的发车数是看当前站点之前收集了多少车、当前站点缺了几辆车
各节点车辆数,Cmax=10;
例1:7 0 2
则 Send=6 , Back=0 ;
例2:7 0 6
则 Send=3 ,Back=1;(而不是发2辆车,回收0辆车,这一点要注意,不然测试点5、7会错误)
更新Send、Back实现方法:
int ts=Send,tc=collect; //为收集车辆数、发车数缓存,便于dfs()调用后恢复
if(collect+num[i]-Cmax/2<0) Send+=-(collect+num[i]-Cmax/2),collect=0; //在本站之前收集到的车辆 < 当前站前所缺的车辆,所以Send要累加,而collect要清0
else collect+=num[i]-Cmax/2; //在本站之前收集到的车辆 >= 当前站前所缺的车辆,所以Send无需增加,而collect要累加
dfs(sp,i,ds+G[now][i],collect);
Send=ts,collect=tc; //恢复dfs()调用前的数据
AC代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;
int Cmax,n,sp,m;
int G[505][505]={},num[505]={},vis[505]={};
int minDis=100000,Send=0,Back=0,minSend=100000,minBack=100000;
vector<int> tpass,pass;
vector<int>::iterator it;
void dfs(int sp,int now,int ds,int collect){
if(now==sp){
Back=collect;
if(ds<minDis){ //本次路径更短
minDis=ds;
minSend=Send;
minBack=Back;
pass=tpass;
}
else if(ds==minDis&&Send<minSend){ //本次路径长度相同,但发出的车更少
minSend=Send;
minBack=Back;
pass=tpass;
}
else if(ds==minDis&&Send==minSend&&Back<minBack){ //本次路径长度、发车数都相等,但回收车辆数更少
minBack=Back;
pass=tpass;
}
return;
}
for(int i=1;i<=n;i++){
if(G[now][i]!=0&&!vis[i]){
vis[i]=1;
tpass.push_back(i);
int ts=Send,tc=collect; //为收集车辆数、发车数缓存,便于dfs()调用后恢复
if(collect+num[i]-Cmax/2<0) Send+=-(collect+num[i]-Cmax/2),collect=0; //在本站之前收集到的车辆 < 当前站前所缺的车辆,所以Send要累加,而collect要清0
else collect+=num[i]-Cmax/2; //在本站之前收集到的车辆 >= 当前站前所缺的车辆,所以Send无需增加,而collect要累加
dfs(sp,i,ds+G[now][i],collect);
Send=ts,collect=tc; //恢复dfs()调用前的数据
tpass.pop_back();
vis[i]=0;
}
}
}
int main()
{
cin>>Cmax>>n>>sp>>m;
for(int i=1;i<=n;i++) cin>>num[i];
int u,v,d;
for(int i=0;i<m;i++){
cin>>u>>v>>d;
G[u][v]=G[v][u]=d;
}
tpass.push_back(0);
dfs(sp,0,0,0);
printf("%d ",minSend>0?minSend:0);
for(it=pass.begin();it!=pass.end();it++) {
cout<<*it;
if((it+1)!=pass.end()) cout<<"->";
else cout<<" ";
}
printf("%d",minBack>0?minBack:0);
return 0;
}