POJ-Domino Effect(最短路)

题目连接: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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值