[ZOJ 1298][POJ 1135] Domino Effect

ZOJ: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1298

POJ: http://poj.org/problem?id=1135


題目大意:

    有n個關鍵骨牌 (1 <= n < 500),m列骨牌。整個多米諾骨牌圖是聯通的。m列骨牌描述如下:a,b,i,表示這排骨牌是在關鍵骨牌a到b之間的,從一頭到另一頭倒下需要i秒。
    總是從n=1的骨牌開始推倒。

    輸出最後倒下的骨牌的倒下時間和位置(最後倒下的是某個關鍵骨牌,或者某兩個關鍵骨牌之間)


解題思路:

    首先每個key domino什麼時候倒下可以抽象爲一個最短路問題,可以用Dijkstra, BellmanFord或者SPFA算出每個key domino倒下的時間。

    接下來計算最後倒下骨牌的位置。由於“If you find several solutions, output only one of them.”,注意到答案可能不只一個,所以我枚舉計算了

1、每條邊最後倒下骨牌倒下的時間(如果邊i->j,有dis[i]>dis[j]-w[i][j],說明不是從i倒到j,那麼最後倒下的骨牌纔是between i and j)

2、每個key domino倒下的時間

    這一步應該有更簡單的方法,或者放在最短路里做,但是數據量不大,就這麼亂搞了……


注意點

1、邊界問題,要測試n==1的時候能不能正常輸出,我因爲這個WA了一次……

2、輸出後加一空行

3、分情況輸出的時候,加n==1的時候匆匆忙忙System # 這一行漏了一次……


源代碼:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <limits.h>
using namespace std;
#define maxn 510

struct edge{int v,w,next;};

bool init(int g[], edge e[],int &n, int &m)
{
    scanf("%d%d", &n, &m);
    if (n==0 && m==0) return false;
    memset(g,255,sizeof(*g)*n);
    for(int i=0,j=0; i<m;i++)
    {
        int a,b,c;
        scanf("%d%d%d", &a, &b, &c);
        a--; b--;
        e[j].v=b; e[j].w=c; e[j].next=g[a]; g[a]=j++;
        e[j].v=a; e[j].w=c; e[j].next=g[b]; g[b]=j++;
    }
    return true;
}

bool bellmanford(int g[], edge e[], int n, int s, int dis[])
{
    bool u[maxn]={0};
    int q[maxn], c[maxn]={0}, h=0, d=1;
    for (int i=0; i<n; i++)
        dis[i]=INT_MAX;
    dis[s]=0; u[s]=true; q[0]=s;
    while (h!=d)
    {
        int i=q[h];
        if (++h==n+1) h=0;
        u[i]=false;
        if (c[i]++==n) return false;
        for (int j=g[i],k; j!=-1; j=e[j].next)
            if (dis[k=e[j].v]>dis[i]+e[j].w)
            {
                dis[k]=dis[i]+e[j].w;
                if (!u[k]) {u[k]=true; q[d++]=k; if(d==n+1) d=0;}
            }
    }
    return true;
}

void solve(int g[], edge e[], int cs, int n, int dis[])
{
    printf("System #%d\n", cs);
    int k=0, k1, k2;
    double time1=0.0, time2=0.0;
    //check the last falling key domino
    for (int i=1; i<n; i++)
        if (dis[i]>dis[k]) k=i;
    time1=1.0*dis[k];
    //check domino between key dominoes
    for (int i=0; i<n; i++)
        for (int j=g[i]; j!=-1; j=e[j].next)
        {
            if (dis[e[j].v]<=dis[i] && dis[e[j].v]>dis[i]-e[j].w && 1.0*(dis[e[j].v]+dis[i]+e[j].w)/2>time2)
            {
                time2=1.0*(dis[e[j].v]+dis[i]+e[j].w)/2;
                k1=(i<e[j].v)?i:e[j].v;
                k2=(i>e[j].v)?i:e[j].v;
            }
        }
    if (time1>time2)
        printf("The last domino falls after %.1lf seconds, at key domino %d.\n\n", time1, k+1);
    else
        printf("The last domino falls after %.1lf seconds, between key dominoes %d and %d.\n\n", time2, k1+1, k2+1);
}

int main(){
    int g[maxn], dis[maxn];
    edge e[maxn*maxn];
    int n, m;
    for (int cs=1; ;cs++)
    {
        if (!init(g, e, n, m)) break;
        if (n==1)
        {
             printf("System #%d\n", cs);
             printf("The last domino falls after 0.0 seconds, at key domino 1.\n\n");
             continue;
        }
        bellmanford(g, e, n, 0, dis);
        solve(g, e, cs, n, dis);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章