纠结了昨天一下午外加晚上快睡觉前的一段时间外加今天上午的一个小时,这道最短路径的题终于AC啦!!!泪奔!!!
我想想该怎么说这个算法呢。
恩。
这道题是寻找多米诺骨牌的最终停下的位置,从牌1开始,如果1连接条路,两条路可以同时开始倒,以后也是,如果key点连接多条路,到达key点时,连接的所有路都开始倒。
我的想法是:
1、用dijkstra找最短路径,从这些最短路径中寻找最长的路。
2、寻找三角形。比如下面这个图(我画的哦~~)黑色数字代表key点,红色代表边长。你所需做的工作就是,从2开始找与2连接的点,
距离为1到2的最短路径+(比如找到3)到1的最短路径+2 3之间的距离,一直找下去,直到这个距离最大。下面这个图的最大值是1到4的最短路径(5)加1到5的最短路径(2)加4 5 之间的距离(5),为12。如果中间不能连接,不进入循环。得到的这个12/2为时间,端点4,5(这个需要在循环中保存)。
3、判断12/2是否比最短路径中的最长路径大,大的话最后一定是在某两个点之间停止。小的话一定是在最短路径中的最长路径的那个key点停止。
中间细节问题都很好想的,我想了好多组测试数据呀。。。1 0,这个数据比较特殊,输出0.0s 1,可以单独处理也可以不用,看自己的算法了。
很开心~~哈哈哈哈哈哈哈哈哈~~排名第二哦~~~第一是用FPC写的,128KB,我用C写的160,哈哈~~~成就感!!!
#include <stdio.h> #include <stdlib.h> #include <memory.h> #include <limits.h> #include <math.h> int main(void) { int n,m,a,b,x,i,j,k,count = 1,flag,aa,bb,temp; int map[502][502],hash[502],now; double dis[502]; double length,mmax,mmin,max; while( scanf("%d %d",&n,&m) && n ) //如果写成&&n&&m 那么1 0 这组数据过不去咧。。 { memset(hash, 0 ,sizeof(hash)); for(i=1; i<=n; i++) //初始化邻接矩阵,对角线上距离都为0 { for(j=1; j<=n; j++) map[i][j] = INT_MAX; map[i][i] = 0; dis[i] = INT_MAX; } for(i=1; i<=m; i++)//输入邻接矩阵,map[a][b] == map[b][a] { scanf("%d %d %d",&a,&b,&x); map[a][b] = x; map[b][a] = x; } now = 1; dis[now] = 0; hash[1] = 1; for(i=1; i<=n ;i++) //Dijkstra 算法 { max = INT_MAX; for(j=1; j<=n ; j++) if( dis[j] - dis[now] - map[now][j] > 0.000001 && map[now][j] != INT_MAX ) dis[j] = dis[now] + map[now][j]; for(j=1; j<=n; j++) if( !hash[j] && max - dis[j] > 0.000001 ) { max = dis[j]; now = j; } hash[now] = 1; } mmax = 0 ;temp = 1; for(i=1; i<=n; i++)//找最短路径的最大值 if(dis[i] > mmax) { mmax = dis[i]; temp = i; } mmin = 0;flag = 1; for(i=1; i<=n; i++) //寻找从1出发的两条最短路径到达的点以及这两点之间的距离的和的最大值 for(j=1; j<=n; j++) { if( !fabs(dis[i] - map[i][j] - dis[j] )< 0.0000001) if( dis[i] + map[i][j] -mmax > 0.0000001 && map[i][j]!=INT_MAX ) { flag = 0; //标记是否在key点停止还是在边上停止 if( dis[i] + map[i][j] + dis[j] > mmin ) { mmin = dis[i] + map[i][j] + dis[j]; aa = i; bb = j; } } } if(flag == 0 && (dis[aa] + dis[bb] +map[aa][bb])/2 < mmax ) //如果找到最长距离的时间比最短路径的时间小,则最终在key点停止 { flag = 1; } printf("System #%d/n",count++); if( flag ) { printf("The last domino falls after %.1lf seconds, at key domino %d./n",mmax,temp); } else { length = (dis[aa] + dis[bb] +map[aa][bb])/2; printf("The last domino falls after %.1lf seconds, between key dominoes %d and %d./n",length,aa<bb?aa:bb,aa>bb?aa:bb); }//这个输出我是按从小点到大点输出的,不按这个顺序也可以。 printf("/n"); } return 0; }