PAT1018 公共自行车管理 (图论/最短路dijkstra变形/贪心/dfs)

公共自行车管理

题目大意:
每个结点中自行车存放的数量小于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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}

你可能感兴趣的:(图论,最短路,dfs)