题目描述
题目大意:沿途走过当前城市的时候,可以根据当前已经收集的单车进行发放或者索要。要保证走过的路径所有城市都为perfect 后面的城市不能给前面的城市发放,也就是后面如果多出5辆不能填给前面的
知识点:最短路,深搜(至于这个为什么不是贪心目前不晓得)
先求出所有的最短路,然后搜索所有最短路的收集或发放情况。
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 510;
const int inf=1e9;
int cmax,n,sp,m;
vector<int> path,tempath;//一个保存最终的最优路径,一个保存当前搜索到的路径
vector<int> pre[N];//保存从当前节点的所有可能路径
int dist[N],v[N],g[N][N],s[N];
int min_need = inf;
int min_back = inf;
void dfs(int u){//深搜所有最短路径中的最佳方案
tempath.push_back(u);
if(u == 0){
int tem_need=0,tem_back=0;
for(int i = tempath.size()-1;i >= 0;i--){
int uu = tempath[i];
if(s[uu] < 0){//说明是需要单车
if(tem_back < -s[uu]){//收集来的还不够
tem_need += -s[uu] - tem_back;
tem_back = 0;
}else{
tem_back -= -s[uu];
}
}else{
tem_back += s[uu];
}
}
if(tem_need < min_need || (tem_need == min_need && tem_back < min_back)){
min_need = tem_need;
min_back = tem_back;
path = tempath;
}
}
for(int i = 0;i < pre[u].size();i++){
dfs(pre[u][i]);
tempath.pop_back();//搜索完该点需要恢复现场
}
}
int main(){
memset(g,0x3f,sizeof g);
memset(dist,0x3f,sizeof dist);
cin>>cmax>>n>>sp>>m;
for(int i = 1;i <= n;i++){
cin>>s[i];
s[i] = s[i] - cmax/2;//先预处理该站点是要收集还是发放
}
for(int i = 0;i < m;i++){
int a,b;
cin>>a>>b>>g[a][b];
g[b][a] = g[a][b];
}
dist[0] = 0;
for(int i = 0;i <= n;i++){
int t = -1;
for(int j = 0;j <= n;j++)
if(!v[j] && (t == -1 || dist[j] < dist[t]))
t = j;
v[t] = 1;
for(int j = 0;j <= n;j++){
if(!v[j] && dist[t] + g[j][t] <= dist[j]){
if(dist[t] + g[j][t] == dist[j]){
pre[j].push_back(t);
}else{
pre[j].clear();
pre[j].push_back(t);
dist[j] = dist[t] + g[j][t];
}
}
}
}
dfs(sp);
cout<<min_need<<" ";
for(int i = path.size()-1;i >= 0;i--){
if(i != 0)
cout<<path[i]<<"->";
else cout<<path[i];
}
cout<<" "<<min_back;
return 0;
}