1 题目大意
你知道多米诺骨牌除了用来玩多米诺骨牌游戏外,还有其他用途吗?多米诺骨牌游戏:取一些多米诺骨牌,竖着排成连续的一行,两张骨牌之间只有很短的空隙。如果排列得很好,当你推倒第1 张骨牌,会使其他骨牌连续地倒下(这就是短语“多米诺效应”的由来)。然而当骨牌数量很少时,这种玩法就没多大意思了,所以一些人在80 年代早期开创了另一个极端的多米诺骨牌游戏:用上百万张不同颜色、不同材料的骨牌拼成一幅复杂的图案。他们开创了一种流行的艺术。在这种骨牌游戏中,通常有多行骨牌同时倒下。你的任务是编写程序,给定这样的多米诺骨牌游戏,计算最后倒下的是哪一张骨牌、在什么时间倒下。这些多米诺骨牌游戏包含一些“关键牌”,他们之间由一行普通骨牌连接。当一张关键牌倒下时,连接这张关键牌的所有行都开始倒下。当倒下的行到达其他还没倒下的关键骨牌时,则这些关键骨牌也开始倒下,同样也使得连接到它的所有行开始倒下。每一行骨牌可以从两个端点中的任何一张关键牌开始倒下,甚至两个端点的关键牌都可以分别倒下,在这种情形下,该行最后倒下的骨牌为中间的某张骨牌。假定骨牌倒下的速度一致。
输入描述:
输入文件包含多个测试数据,每个测试数据描述了一个多米诺骨牌游戏。每个测试数据的第1 行为两个整数:n 和m,n 表示关键牌的数目,1≤n<500;m 表示这n 张牌之间用m 行普通骨牌连接。n 张关键牌的编号为1~n。每两张关键牌之间至多有一行普通牌,并且多米诺骨牌图案是连通的,也就是说从一张骨牌可以通过一系列的行连接到其他每张骨牌。接下来有m 行,每行为3 个整数:a、b 和t,表示第a 张关键牌和第b 张关键牌之间有一行普通牌连接,这一行从一端倒向另一端需要t 秒。每个多米诺骨牌游戏都是从推倒第1 张关键牌开始的。输入文件最后一行为n = m = 0,表示输入结束。
输出描述:
对输入文件中的每个测试数据,首先输出一行"System #k",其中k 为测试数据的序号;然后再输出一行,首先是最后一块骨牌倒下的时间,精确到小数点后一位有效数字,然后是最后倒下骨牌的位置,这张最后倒下的骨牌要么是关键牌,要么是两张关键牌之间的某张普通牌。输出格式如样例输出所示。如果存在多个解,则输出任意一个。每个测试数据的输出之后输出一个空行。
2 题目分析
这是一道最短路径题目,但是要判断哪种最优解的情况。设res为最后一张牌倒下的时刻,pos_i和pos_j记录的是最后倒下的关键牌的标号,初始化都为-1。
a) 如果最后一张倒下的是关键牌。利用Dijkstra 算法求第1 张关键牌到其他每张关键牌的最短路径,保存在dist[i]。然后取dist[i]的最大值,设为res,pos_i记录关键牌序号。
b) 如果最后一张倒下的是两张关键牌之间的普通牌。设该行两端的关键牌为i 和j,他们以每秒一个单位的速度相向而行,设i和j分别经过t1和t2秒相遇,i和j之间的距离为g[i][j],求i和j在什么时刻相遇。不难列出方程:t1+t2=g[i][j],dis[i]+g[i][j]=dis[j]+g[i][j]。则i和j相遇的时刻为t=(dist[i] + dist[j] +g[i][j])/2.0。res=min(res,t)。pos_i和pos_j记录两张关键牌的序号。(注意:要满足dis[i]+g[i][j]>dis[j]并且dis[j]+g[i][j]>dis[i]才应该计算t值)
c) 如果pos_j=-1,则是a情况;否则是b情况(如果b情况成立,pos_j的值应该改变了)。
3代码
#include<stdio.h>
#include<string.h>
#define MAXV 501
#define MAXINT 999999999
double res;
int pos_a,pos_b;
int g[MAXV][MAXV],vis[MAXV],dis[MAXV],p[MAXV];
void initial()
{
int i,j;
for(i=0;i<MAXV;i++)
{
vis[i]=0;
dis[i]=MAXINT;
p[i]=-1;
for(j=0;j<MAXV;j++)
{
if(i!=j)
g[i][j]=MAXINT;
}
}
res=-MAXINT;
pos_a=-1;
pos_b=-1;
}
void dijkstra(int nvertex,int start)
{
int v,i,j,distance;
dis[start]=0;
v=start;
while(!vis[v])
{
vis[v]=1;
for(i=1;i<=nvertex;i++)
{
if(!vis[i] && dis[i]>(dis[v]+g[v][i]))
{
dis[i]=dis[v]+g[v][i];
p[i]=v;
}
}
distance=MAXINT;
for(i=1;i<=nvertex;i++)
{
if(!vis[i] && dis[i]<distance)
{
distance=dis[i];
v=i;
}
}
}
for(i=1;i<=nvertex;i++)
{
if(res<dis[i])
{
res=dis[i];
pos_a=i;
}
}
double temp;
for(i=1;i<=nvertex;i++)
{
for(j=1;j<=nvertex;j++)
{
if(i!=j && g[i][j]<MAXINT && dis[i]+g[i][j]>dis[j] && dis[j]+g[i][j]>dis[i])
{
temp=1.0*(dis[i]+dis[j]+g[i][j])/2;
if(res<temp)
{
res=temp;
if(i<j)
{
pos_a=i;
pos_b=j;
}
else
{
pos_a=j;
pos_b=i;
}
}
}
}
}
}
int main()
{
int n,m,count=1;
while(2==scanf("%d%d",&n,&m))
{
if(0==n && 0==m)
break;
initial();
int i,a,b,c;
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
g[a][b]=g[b][a]=c;
}
dijkstra(n,1);
printf("System #%d\n",count++);
if(-1==pos_b)
printf("The last domino falls after %.1lf seconds, at key domino %d.\n\n",res,pos_a);
else
printf("The last domino falls after %.1lf seconds, between key dominoes %d and %d.\n\n",res,pos_a,pos_b);
}
return 0;
}