道路网(map)

34 篇文章 0 订阅
33 篇文章 0 订阅

【一句话题意】C 国的道路网络由m条双向线路组成,有n个城市在道路网络上。每条线路途经一些城市(可能会经过多次同一城市),最多有li个城市,位于线路上的两个城市a,b 通过i 号线路互相抵达的费用为w[i][a] + w[i][b]。现在有T个询问,询问两城市互相到达的最小费用。
n<=1e5;m<=300;li,T,w[i][j]<=2000。
【分析】此题暴力spfa可以骗到50分,对于第一遍的暴力是一个不错的选择。
回归到正解,我们可以看成每次进出站记一次站点的费用。因为m值较小,我们可以对每两条线路之间的转站进行floyd。每次询问时,枚举从a、b两点出发各个线路的转站,费用再加上两个站点的出入站费,求最小值。
【code】

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxm=310;
const int maxl=2010;
const int maxn=1e5+1000;
int n,m;
struct E{
	int id,c,nxt;
}road[maxm*maxl];
int head[maxn],tot;
int f[maxm][maxm];
inline void read(int &x){
	x=0;char tmp=getchar();
	while(tmp<'0'||tmp>'9') tmp=getchar();
	while(tmp>='0'&&tmp<='9') x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
}
inline void add_road(int x,int id,int c){
	road[tot].id=id;
	road[tot].c=c;
	road[tot].nxt=head[x];
	head[x]=tot++;
}
int main(){
	memset(head,-1,sizeof(head));
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int x,w,cnt;read(cnt);
		for(int j=1;j<=cnt;j++)
			read(x),read(w),add_road(x,i,w);
	}
	for(int i=1;i<=m;i++)
		for(int j=1;j<=m;j++)
			f[i][j]=1<<29;
	for(int i=1;i<=m;i++)
		f[i][i]=0;
	for(int i=1;i<=n;i++){//node
		for(int j=head[i];j!=-1;j=road[j].nxt){//line1
			for(int k=head[i];k!=-1;k=road[k].nxt){//line2
				if(j==k) continue;
				int x=road[j].id,y=road[k].id,w=road[j].c+road[k].c;
				f[y][x]=f[x][y]=min(f[x][y],w);
			}
		}
	}
	for(int k=1;k<=m;k++)
		for(int i=1;i<=m;i++)
			for(int j=1;j<=m;j++)
				f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
	int a,b;read(a),read(b);
	while(a||b){
		int ans=-1;
		for(int i=head[a];i!=-1;i=road[i].nxt){
			int u=road[i].id;
			for(int j=head[b];j!=-1;j=road[j].nxt){
				int v=road[j].id;
				if(f[u][v]==1<<29) continue;
				if(road[i].c+road[j].c+f[u][v]<ans||ans==-1) ans=road[i].c+road[j].c+f[u][v];
			}
		}
		printf("%d\n",ans);
		read(a),read(b);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值