欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PAT 甲 1131 Subway Map (30 分)

程序员文章站 2024-03-17 14:17:37
...

1131 Subway Map (30 分)

题目大意:
给一张地图,无向,给出n个行线,起点终点,不同行线要通过中转站转车,问最少经过多少站到达,如果站数相等,再根据最少转车次数判断。
要求输出站数,和每次转车的行线,这条行线的起点终点。
输入:
4
7 1001 3212 1003 1204 1005 1306 7797
9 9988 2333 1204 2006 2005 2004 2003 2302 2001
13 3011 3812 3013 3001 1306 3003 2333 3066 3212 3008 2302 3010 3011
4 6666 8432 4011 1306
3
3011 3013
6666 2001
2004 3001
输出:
2
Take Line#3 from 3011 to 3013.
10
Take Line#4 from 6666 to 1306.
Take Line#3 from 1306 to 2302.
Take Line#2 from 2302 to 2001.
6
Take Line#2 from 2004 to 1204.
Take Line#1 from 1204 to 1306.
Take Line#3 from 1306 to 3001.
样例图:
PAT 甲 1131 Subway Map (30 分)


真是难到我了,寻思着我写的题也不少了啊,怎么一点思路没得,应该是没吃饭引起的。

这题我开始想着用点来做,但是每个点可能在多个行线上,那么在判断的时候这个点u和他所连接的点v,即使开了个二维数组,用来保存每个点所包含的行线,那么在过从u点到v点,也根本没有办法判断是不是换行线了,因为就算两点行线不同,也有可能是一个行线上的,就算两点行线有相同的,也有可能是不同行线转来的(4011-1306-7797)到此死机。

这题根本问题我就想错了,其实可以继续想,如果从点分配行线不行,那么从边呢?4011-1306这条边是1,1306-7797这条边是2,那么就解决了行线处理问题,那么我们就需要另一个二维数组来保存边,边序号就对应点,再查询两点边颜色的时候,对应点来找到边序号从而找到对应颜色。

因为找最小而且有环,所以加个vis[]数组,最后别忘记加04d,ok


#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7,INF = 0x3f3f3f3f;
int line[N][11],link[N][11];//行线颜色,每个点的邻接点。 
int vis[N],num[N],zpath[N],path[N];//num[u]是u点连出边的总数 
int n,mzc,mcs;
int getline(int u,int v){
	for(int i=1;i <= num[u];i++){ //暴力找点,通过点找到行线颜色 
		if(link[u][i] == v) return line[u][i];
	}
}
void dfs(int now,int preline,int cs,int zc,int ed){ //当前点,上个行线,坐站数,转车数,终点 
	path[cs] = now;
	if(cs > mcs || (cs == mcs && zc > mzc) ) return; //剪枝 
	if(now == ed){
		mcs = cs,mzc = zc;
		for(int i=0;i <= cs;i++)
		zpath[i] = path[i];
		return;
	}
	for(int i=1;i <= num[now];i++){
		int v = link[now][i];
		if(!vis[v]){
			vis[v] = 1;
			int line = getline(now,v);
			if(line == preline) dfs(v,line,cs+1,zc,ed);
			else dfs(v,line,cs+1,zc+1,ed);
			vis[v] = 0;
		}
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i <= n;i++){
		int k,u;scanf("%d%d",&k,&u);
		for(int j=2;j <= k;j++){
			int v;scanf("%d",&v);
			link[u][++num[u]] = v;
			line[u][num[u]] = i;
			link[v][++num[v]] = u;
			line[v][num[v]] = i;
			u = v;
		}
	}
	int k;scanf("%d",&k);
	for(int i=1;i <= k;i++){
		memset(vis,0,sizeof vis);
		int st,ed;scanf("%d%d",&st,&ed);
		mcs = mzc = INF;
		dfs(st,-1,0,-1,ed); //这里我们转车数要从-1开始,因为起点行线是-1,那么不管第二个点是什么,行线都要+1 
		printf("%d\n",mcs);
		int line1 = getline(zpath[0],zpath[1]);
		for(int i=2;i <= mcs;i++){
			int line2 = getline(zpath[i-1],zpath[i]);
			if(line2 != line1){
				printf("Take Line#%d from %04d to %04d.\n",line1,st,zpath[i-1]);
				line1 = line2;
				st = zpath[i-1];
			}
		}
		printf("Take Line#%d from %04d to %04d.\n",line1,st,ed);
	}
	return 0;
}