题目连接:http://poj.org/problem?id=1135
题目大意:多米诺骨牌有n张关键牌,即n个结点,由m条边连结。关键牌之间放有非关键牌,也即每两个关键牌之间传递是需要时间t秒的。每次从推到第一张关键牌开始,求所有的牌倒下的时间,包括非关键牌倒下。
好久不做图论的题了,这次又重新温习了一下Dijkstra算法,没想到被几个鸡肋的问题卡了一下,说多了都是泪。
题目分析:求最长时间无非是求从结点1到其他结点的最长路径,但还有一个问题就是,答案并不一定是结点1到其他结点的最长路径,还有可能最后倒下的是非关键牌,也就是说可能是结点与结点之间的牌。这种情况的处理方法是,我们遍历所有相连的点,他们之间普通牌最后倒下的时间就是源点到它俩的最短路径加上他们边上权值的平均值,即(dist[i]+dist[j]+edge[i][j])/2。
Source code:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#define debug "output for debug\n"
#define pi (acos(-1.0))
#define eps (1e-8)
#define inf 0x3f3f3f3f
#define ll long long int
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
using namespace std;
const int mod = 1000000007;
const int Max = 505;
int edge[Max][Max];
int s[Max];
int dist[Max];
int n,m;
void DJ(int v0)
{
int i,j,k;
for(i=1; i<=n; i++)
{
dist[i]=edge[v0][i];
s[i]=0;
}
s[v0]=1;
dist[v0]=0;
for(i=1; i<n; i++)
{
int mi=inf,u=v0;
for(j=1; j<=n; j++)
{
if(!s[j]&&dist[j]<mi)
{
u=j;
mi=dist[j];
}
}
s[u]=1;
for(k=1; k<=n; k++)
{
if(!s[k]&&edge[u][k]<inf&&dist[u]+edge[u][k]<dist[k])
{
dist[k]=edge[u][k]+dist[u];
}
}
}
}
int main()
{
int u,v,w,cnt=1;
while(scanf("%d%d",&n,&m)&&(m+n)!=0)
{
memset(dist,0,sizeof dist);
memset(edge,0,sizeof edge);
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&u,&v,&w);
edge[u][v]=w;
edge[v][u]=w;
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(j==i)
edge[i][j]=0;
else if(edge[i][j]==0)
edge[i][j]=inf;
}
}
//puts("sss");
DJ(1);
double ans=-1;
int a,a1=0,a2=0,tmp=-1;
for(int i=1; i<=n; i++)
{
if(tmp<dist[i])
{
tmp=dist[i];
a=i;
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(edge[i][j]<inf)
{
double t=((dist[i]+dist[j]+edge[i][j])/2.0);
if(t>ans)
{
ans=t;
a1=i;
a2=j;
}
}
}
}
//cout<<tmp<<" "<<ans<<endl;
printf("System #%d\n",cnt++);
if(tmp*1.0>=ans)
{
ans=(double)tmp;
printf("The last domino falls after %.1f seconds, at key domino %d.\n\n",ans,a);
}
else
{
printf("The last domino falls after %.1f seconds, between key dominoes %d and %d.\n\n",ans,a1,a2);
}
}
return 0;
}
在POJ上这道题最好不用%.1lf,因为这个问题WA了好几发,注意看他的discuss。