公共自行车管理
题目大意:
每个结点中自行车存放的数量小于C/2向下取整的话就加到C/2,大于C/2向下取整的话就减到C/2
给一个起点(0),给一个终点(S)然后有三个条件
- 首先要路径最短
- 在此基础上最初带去的自行车越少越好
- 在此在此基础上最终带回来的自行车越少越好
解题思路:
首先跑一下最短路dijkstra是没问题的,但是这个只能筛选出满足第一个条件的路径,所以要变形一下,记录一下从起点(0)到各个点的最短距离dist[i] ,然后如果dist[i]+g[i][s] (i到S(终点)的距离)= distS的话,这个点也满足第一个条件,然后从这个点开始跑dfs判断是否满足第二第三个条件,如果满足,记录下来然后输出即可。
Code:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_set>
#include<unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int maxn=1e3+7;
int C,n,S,m;
int c[maxn],g[maxn][maxn],dist[maxn];
bool vis[maxn];
vector<int> path,ans;
int send=inf,bring=inf;
void dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[S]=0;
for(int i=0;i<n;i++){
int t=-1;
for(int j=0;j<=n;j++){
if(!vis[j]&&(t==-1||dist[j]<dist[t])) t=j;
}
vis[t]=true;
for(int j=0;j<=n;j++) dist[j]=min(dist[j],dist[t]+g[t][j]);
}
}
void dfs(int u,int s,int mins){
if(u){
s-=(C+1)/2-c[u]; //除以二向上取整 , 当u为0的时候跳过
mins=min(mins,s);
}
if(u==S){
int sd=abs(min(0,mins));
int bg=s+sd;
if(sd<send) ans=path,send=sd,bring=bg; //ans为最终答案,把path赋值进来
else if(sd==send&&bg<bring) ans=path,bring=bg;
return ;
}
for(int i=1;i<=n;i++){
if(dist[u]==g[u][i]+dist[i]){
path.push_back(i);
dfs(i,s,mins);
path.pop_back(); //弹出刚加进来的这个
}
}
}
int main()
{
cin>>C>>n>>S>>m;
for(int i=1;i<=n;i++) cin>>c[i];
memset(g,0x3f,sizeof g);
for(int i=1;i<=m;i++){
int x,y,z;
cin>>x>>y>>z;
g[x][y]=g[y][x]=min(g[x][y],z);
}
dijkstra();
path.push_back(0);
dfs(0,0,0);
cout<<send<<" "<<0;
for(int i=1;i<ans.size();i++){
cout<<"->"<<ans[i];
}
cout<<" "<<bring<<"\n";
return 0;
}