题意:本题的要求是推倒第一张关键牌后,最后倒下的牌的位置及时间。
思路:
最后倒下的牌只有两种情形:⑴最后倒下的牌就是关键牌 ⑵最后倒下的牌是两张关键牌之间的普通牌。所以我们需要判断最后到底是那种情形。
1.计算每一张关键牌倒下的时间。取最大值maxtime1。
2.计算每一行完全倒下的时间。每一行倒下的时间t = (time[i] + time[j] + edge[i][j])/2.0,去最大值maxtime2。
3.如果maxtime2 > maxtime1 则最后倒下的牌是普通牌,否则是关键牌。
代码:
#include <iostream>
#include <cstdio>
using namespace std;
const int inf = 10000000;
const int maxn = 505;
int edge[maxn][maxn];
int Time[maxn];
bool vis[maxn];
int n,m;
bool Input(){
int u,v,w;
cin>>n>>m;
if(n == 0 && m == 0)
return false;
for(int i = 0; i <= n; i++){
for(int j = 0; j <= n; j++)
edge[i][j] = inf;
}
for(int i = 0; i < m; i++){
cin>>u>>v>>w;
edge[u][v] = edge[v][u] = w;
}
return true;
}
void Dijkstra(){
for(int i = 1; i <= n; i++){
vis[i] = 0; Time[i] = edge[1][i];
}
vis[1] = 1; Time[1] = 0;
for(int i = 0; i < n-1; i++){
int min = inf;
int v;
for(int j = 1; j <= n; j++){
if(!vis[j] && Time[j] < min){
min = Time[j]; v = j;
}
}
vis[v] = 1;
for(int j = 1; j <= n; j++){
if(!vis[j] && Time[v] + edge[v][j] < Time[j]){
Time[j] = Time[v] + edge[v][j];
}
}
}
}
void Solve(){
static int cnt = 0;
Dijkstra();
double maxtime1 = -inf;
int pos;
for(int i = 1; i <= n; i++){
if(Time[i] > maxtime1){
maxtime1 = Time[i]; pos = i;
}
}
double maxtime2 = -inf;
int pos1,pos2;
for(int i = 1; i <= n; i++){
for(int j = i+1; j <=n; j++){
if(edge[i][j] == inf)
continue;
double t = (Time[i] + Time[j] + edge[i][j]) / 2.0;
if(t > maxtime2){
maxtime2 = t;
pos1 = i;
pos2 = j;
}
}
}
printf("System #%d\n",++cnt);
printf("The last domino falls after ");
if(maxtime2 > maxtime1){
printf("%.1lf seconds, between key dominoes %d and %d.\n\n",maxtime2,pos1,pos2);
}
else{
printf("%.1lf seconds, at key domino %d.\n\n",maxtime1,pos);
}
}
int main(){
while(Input()){
Solve();
}
return 0;
}