pat-1018(图论+dfs+dij)

pat-1018

题意:

有n个共享单车停车点(编号1-n),编号0是共享单车的分发总站,求出从0到st上的最短路径上所需要发放或

收取的最少的单车的数量。

思路:

还是图论知识不牢固,今后三天多练练图论的题目。(参考文章

首先找最短路径,然后在已知的几条最短路径上求出需要发放还是回收自行车,再求出它们的最小值。

(1)求出最短路径,可以用dij算法来求,由于路径不唯一,所以可以用邻接表记录这些路径。

(2)按照求好的最短路径更新所需的发放或者回收的自行车的数量。

 

反思:

(1)记录多条路径时可以用邻接表表示

(2)深搜一定要回溯。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 100100;
const int INF = 99999999;
int vis[maxn],dis[maxn],mp[550][550],wei[maxn];
vector <int> pre[550],path,tmpath;
int mineed,miback;
void dfs(int u)
{
	tmpath.push_back(u);
	if(u==0){
		int v,i,need=0,back=0;
		for(i=tmpath.size()-1;i>=0;i--){
			v=tmpath[i];
			if(wei[v]>0){
				back+=wei[v];
			}
			else{
				if(back>(0-wei[v])){
					back+=wei[v];
				}
				else{
					need+=((0-wei[v])-back);
					back=0;
				}
			}
		}
		if(need<mineed){
			mineed=need;
			miback=back;
			path=tmpath;
		}
		else if(need==mineed&&back<miback){
			miback=back;
			path=tmpath;
		}
		tmpath.pop_back();
		return ;
	}
	for(int i=0;i<pre[u].size();i++)
	dfs(pre[u][i]);
	tmpath.pop_back();
}
int main(void)
{
	int n,m,k,st,i,j,x,z,y,cmx;
	scanf("%d%d%d%d",&cmx,&n,&st,&m);
	for(i=1;i<=n;i++){
		scanf("%d",&wei[i]);
		wei[i]-=cmx/2;dis[i]=INF;
	}
	for(i=0;i<=n;i++)
		for(j=0;j<=n;j++) mp[i][j]=INF;
	for(i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		mp[x][y]=mp[y][x]=z;
	}
	memset(vis,0,sizeof(vis));
	dis[0]=0;
	for(i=1;i<=m;i++){
		int mi=INF,pos=-1;
		for(j=0;j<=n;j++)
		if(vis[j]==0&&mi>dis[j]){
			mi=dis[j];pos=j;
		}
		if(pos==-1) break;
		vis[pos]=1;
		for(j=0;j<=n;j++){
			if(vis[j]==0&&mp[pos][j]!=INF){
				if(dis[j]>dis[pos]+mp[pos][j]){
					dis[j]=dis[pos]+mp[pos][j];
					pre[j].clear();
					pre[j].push_back(pos);
				}
				else if(dis[j]==dis[pos]+mp[pos][j]){
					pre[j].push_back(pos);
				}
			}
		}
	}
	mineed=INF,miback=INF;
	tmpath.clear();
	dfs(st);
	printf("%d 0",mineed);
	for(i=path.size()-2;i>=0;i--) printf("->%d",path[i]);
	printf(" %d",miback);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值