交通运输线

问题 A: 交通运输线

题目描述

战后有很多城市被严重破坏,我们需要重建城市。然而,有些建设材料只能在某些地方产生。因此,我们必须通过城市交通,来运送这些材料的城市。由于大部分道路已经在战争期间完全遭到破坏,可能有两个城市之间没有道路。当然在运输线中,更不可能存在圈。 
现在,你的任务来了。给你战后的道路情况,我们想知道,两个城市之间是否存在道路,如果存在,输出这两个城市之间的最短路径长度。 

输入

第一行一个整数Case(Case<=10)表示测试数据组数。 
每组测试数据第一行三个整数N,M和C (2<=N<=10, 000) (0<=M<10, 000) (1<=c<=1000000)共有N个城市,现存M条边,共有C对运输需求。 
接下来M行,每行三个整数A和B,D(1<=A,B<=N,A不等于B)表示从A到B有一条直接的公路,且距离为D。 
最后C行,每行两个整数,S和T(1<=S,T<=N,S不等于T),即询问从S到T的最短路径长度。 

输出

共Case行,否存在从S到T的路径,则输出最短路径,否则输出“Not connected”。

样例输入

1
5 3 2
1 3 2
2 4 3
5 2 3
1 4
4 5

样例输出

Not connected
6
    初看此题,便注意到了这句“当然在运输线中,更不可能存在圈。 ”,也就是说,该图是森林,对于任意两点,要么没有路径,要么
存在唯一路径,所以很容易便想到了树上LCA,而本人用的方法则是tarjan求公共祖先,对于在树上任意两点{u,v},设它们公共祖先
为p,dis[]表示这个点到这棵树树根的距离,于是有两点之间距离=dis[u]+dis[v]-2*dis[p],这个式子可以通过画一棵树很容易得出。
    调了一个多小时。。。哭晕,先是用边表,然而却出现RE和TL,然后改为邻接表,竟然AC了,我将两段代码都放在下面,如果有
路过的神犇可以帮我看看。
RE的代码(边表)
#include
       
       
        
        
#include
        
        
         
         
#define N1 10005
#define N2 1000005 
using namespace std;
int T,n,m,c,cnt,qcnt;
int f[100005],flag[N1],vis[N1],ans[N2],head[N1],next[N1],to[N1],len[N1],qhead[N2],qto[N2],qnext[N2],id[N2],dis[N1];
void init(){
	int i;
	for (i=1;i<=100000;i++) f[i]=i;
	memset(flag,0,sizeof(flag));
	memset(ans,-1,sizeof(ans));
	memset(head,0,sizeof(head));
	memset(to,0,sizeof(to));
	memset(len,0,sizeof(len));
	memset(qhead,0,sizeof(qhead));
	memset(qto,0,sizeof(qto));
	memset(id,0,sizeof(id));
	cnt=0;qcnt=0;
}
void addedge(int u,int v,int p){
	next[++cnt]=head[u];to[cnt]=v;len[cnt]=p;head[u]=cnt;
}
void addqedge(int u,int v,int p){
	qnext[++qcnt]=qhead[u];qto[qcnt]=v;id[qcnt]=p;qhead[u]=qcnt;
}
int find(int x){
	if (f[x]==x) return x;
	return f[x]=find(f[x]);
}
void tarjan(int u){
	vis[u]=1;
	flag[u]=1;
	int i;
	for (i=head[u];i!=0;i=next[i]){
		int v=to[i];
		if (!flag[v]){
			dis[v]=dis[u]+len[i];
			tarjan(v);
			f[v]=u;
		}
	}
	for (i=qhead[u];i!=0;i=qnext[i]){
		int v=qto[i],x=id[i];
		if (flag[v] && vis[v])
			ans[x]=dis[u]+dis[v]-2*dis[find(v)];
	}
}
int main(){
	scanf("%d",&T);
	while (T--){
		init();
		int i;
		scanf("%d%d%d",&n,&m,&c);
		for (i=1;i<=m;i++){
			int u,v,p;
			scanf("%d%d%d",&u,&v,&p);
			addedge(u,v,p);
			addedge(v,u,p);
		}
		for (i=1;i<=c;i++){
			int u,v;
			scanf("%d%d",&u,&v);
			addqedge(u,v,i);
			addqedge(v,u,i);
		}
		for (i=1;i<=n;i++){
			if (!flag[i]){
				dis[i]=0;
				memset(vis,0,sizeof(vis)); 
				tarjan(i);
			}
		}
		for (i=1;i<=c;i++){
			if (ans[i]==-1) 
				printf("Not connected\n");
			else
				printf("%d\n",ans[i]);
		}
	}
	return 0;
}
        
        
       
       
 AC的代码(邻接表)

  
  
#include
     
     
      
      
#include
      
      
       
       
#include
       
       
        
        
#define N1 10005
#define N2 100005
#define N3 1000005 
using namespace std;
int T,n,m,c;
int flag[N1],vis[N1],dis[N1],f[N2],ans[N3];
struct node1{
	int v,len;
};
struct node2{
	int v,id;
};
vector 
        
        
         
          edge[N1];
vector 
         
         
           qedge[N1]; void init(){ int i; for (i=1;i<=100000;i++) f[i]=i; memset(flag,0,sizeof(flag)); memset(ans,-1,sizeof(ans)); for (i=1;i<=10000;i++){ edge[i].clear(); qedge[i].clear(); } } int find(int x){ if (f[x]==x) return x; return f[x]=find(f[x]); } void tarjan(int u){ vis[u]=1; flag[u]=1; int i; for (i=0;i 
           
         
        
        
       
       
      
      
     
     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值