Description
现在是晚餐时间,而母牛们在外面分散的牧场中。农民约翰按响了电铃,所以她们开始向谷仓走去。你的工作是要指出哪只母牛会最先到达谷仓(在给出的测试数据中,总会有且只有一只最快的母牛)。在挤奶的时候(晚餐前),每只母牛都在她自己的牧场上,一些牧场上可能没有母牛。每个牧场由一条条道路和一个或多个牧场连接(可能包括自己)。有时,两个牧场(可能是字母相同的)之间会有超过一条道路相连。至少有一个牧场和谷仓之间有道路连接。因此,所有的母牛最后都能到达谷仓,并且母牛总是走最短的路径。当然,母牛能向着任意一方向前进,并且她们以相同的速度前进。牧场被标记为'a'..'z'和'A'..'Y',在用大写字母表示的牧场中有一只母牛,小写字母中则没有。谷仓的标记是'Z',注意没有母牛在谷仓中。
注意'm'和'M'不是同一个牧场 否则错误 上面的意思是说:输入数据中可能会同时存在M,m(郁闷ing),比如
M a a m m z
Input
第 1 行: 整数 P(1<= P<=10000),表示连接牧场(谷仓)的道路的数目。
第 2 ..P+1行: 用空格分开的两个字母和一个整数:
被道路连接牧场的标记和道路的长度(1<=长度<=1000)。
Output
单独的一行包含二个项目: 最先到达谷仓的母牛所在的牧场的标记,和这只母牛走过的路径的长度。
Sample Input
5
A d 6
B d 3
C e 9
d Z 8
e Z 3
Sample Output
B 11
【分析】
算法:SPFA
输入的时候存边,然后离散化处理,建立对应表,将编号与字母对应。SPFA时从'Z'开始倒着找最短路,最后排序后,找到第一个有牛的就输出。
【代码】
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<ctime> #include<iostream> #include<algorithm> using namespace std; const int INF=0x7FFFFFFF; queue<int>Q; int P,tot,totm,S,x[20005],y[20005],z[20005],next[20005],last[200]; int dis[200],f[200],rank[200]; char anti_f[200]; bool cow[200],mark[200]; void _qst_dis(int l,int r) { int i=l,j=r,md=dis[(i+j)>>1]; while(i<=j) { while(dis[i]<md) i++; while(dis[j]>md) j--; if(i<=j) { swap(dis[i],dis[j]); swap(rank[i],rank[j]); i++;j--; } } if(l<j) _qst_dis(l,j); if(i<r) _qst_dis(i,r); } void _in(int &x) //输入优化 { char t; t=getchar(); while(t<'0'||'9'<t) t=getchar(); for(x=t-'0',t=getchar();'0'<=t&&t<='9';x=x*10+t-'0',t=getchar()); } void _SPFA() { int t; Q.push(S);dis[S]=0;mark[S]=true; while(!Q.empty()) { t=Q.front(); Q.pop(); mark[t]=false; for(int i=last[t];i;i=next[i]) if(dis[y[i]]>dis[t]+z[i]) { dis[y[i]]=dis[t]+z[i]; if(mark[y[i]]==false) { mark[y[i]]=true; Q.push(y[i]); } } } } void _init() { string xs,ys; int a,b; _in(P); for(int i=1;i<=P;i++) { totm++; cin>>xs>>ys; _in(z[totm]); if(f[xs[0]-64]!=0) a=f[xs[0]-64]; else { a=++tot; f[xs[0]-64]=tot; } if(f[ys[0]-64]!=0) b=f[ys[0]-64]; else { b=++tot; f[ys[0]-64]=tot; } anti_f[a]=xs[0];anti_f[b]=ys[0]; //将f逆向对应,以便于输出 if(xs[0]<'Z') cow[a]=true; //记录这个点是否有牛 if(ys[0]<'Z') cow[b]=true; x[totm]=a;y[totm]=b; next[totm]=last[x[totm]]; last[x[totm]]=totm; totm++; x[totm]=b;y[totm]=a;z[totm]=z[totm-1]; //存双向边 next[totm]=last[x[totm]]; last[x[totm]]=totm; } S=f['Z'-64]; //起点的编号 } void _solve() { for(int i=1;i<=tot;i++) { rank[i]=i; //编号,以便排序后知道其原来编号 dis[i]=INF; } _SPFA(); _qst_dis(1,tot); //将dis从小到大排序 for(int i=1;i<=tot;i++) if(cow[rank[i]]&&dis[i]<INF) { printf("%c %d\n",anti_f[rank[i]],dis[i]); return; } } int main() { _init(); _solve(); return 0; }