1. 程式人生 > >CCF之行車路線(迪傑斯特拉演算法,第二次做,90分)

CCF之行車路線(迪傑斯特拉演算法,第二次做,90分)

 問題描述

試題編號: 201712-4
試題名稱: 行車路線
時間限制: 1.0s
記憶體限制: 256.0MB
問題描述:

問題描述

  小明和小芳出去鄉村玩,小明負責開車,小芳來導航。   小芳將可能的道路分為大道和小道。大道比較好走,每走1公里小明會增加1的疲勞度。小道不好走,如果連續走小道,小明的疲勞值會快速增加,連續走s公里小明會增加s2的疲勞度。   例如:有5個路口,1號路口到2號路口為小道,2號路口到3號路口為小道,3號路口到4號路口為大道,4號路口到5號路口為小道,相鄰路口之間的距離都是2公里。如果小明從1號路口到5號路口,則總疲勞值為(2+2)2+2+22=16+2+4=22。   現在小芳拿到了地圖,請幫助她規劃一個開車的路線,使得按這個路線開車小明的疲勞度最小。

輸入格式

  輸入的第一行包含兩個整數nm,分別表示路口的數量和道路的數量。路口由1至n編號,小明需要開車從1號路口到n號路口。   接下來m行描述道路,每行包含四個整數tabc,表示一條型別為t,連線ab兩個路口,長度為c公里的雙向道路。其中t為0表示大道,t為1表示小道。保證1號路口和n號路口是連通的。

輸出格式

  輸出一個整數,表示最優路線下小明的疲勞度。

樣例輸入

6 7 1 1 2 3 1 2 3 2 0 1 3 30 0 3 4 20 0 4 5 30 1 3 5 6 1 5 6 1

樣例輸出

76

樣例說明

  從1走小道到2,再走小道到3,疲勞度為52=25;然後從3走大道經過4到達5,疲勞度為20+30=50;最後從5走小道到6,疲勞度為1。總共為76。

資料規模和約定

  對於30%的評測用例,1 ≤ n ≤ 8,1 ≤ m ≤ 10;   對於另外20%的評測用例,不存在小道;   對於另外20%的評測用例,所有的小道不相交;   對於所有評測用例,1 ≤ n ≤ 500,1 ≤ m ≤ 105,1 ≤ ab ≤ nt是0或1,c ≤ 105。保證答案不超過106。

這道題目是我第二次做了,一開始因為fropen("a.txr","r",stdin)這行程式碼沒有註釋而拿了0分。後來發現問題之後,顯示拿了80分。在仔細閱讀題幹,發現數據型別設定有問題,當我把便令改為long long型別之後,最終拿下了90分。但是今天實在太累了,不打算在鑽研這道題目了。

思路:首先還是套用迪傑斯特拉演算法的模板,寫出基本的程式碼框架。這裡給出的路口數目不超過500個,因此可以直接用二維陣列來構建圖。相比之前的模板不同之處在於,我這裡設定了兩個陣列d_long、d_short,分別儲存每個結點到出發點的大道路徑之和、小道路徑之和。其次,更新點權的時候,需要考慮兩個來源,一個來源就是上一個結點的d_short值,一個來源就是上一個結點的d_long值。在更新過程中要特別注意,會有多條連續的小道相連的情況,嗨喲可能就是大道、小道相互交錯的情況,這也是我為什麼要設定pre陣列來儲存路徑上每個結點的前驅結點的原因。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define MAX 505
#define INF 0x3fffffff
struct Node
{
    long long cost;//記錄小道的長度
    int type;//記錄小道的型別
};

struct Node G[MAX][MAX];
long long d_short[MAX];
long long d_short_square[MAX];
long long d_long[MAX];
long long d[MAX];
int pre[MAX];
int vis[MAX];
int ans=INF;

long long square(long long x)
{
    return x*x;
}

void Djs(int s,int n)
{
    //priority_queue<Dist> q;
    memset(vis,0,sizeof(vis));
    fill(d_long,d_long+MAX,INF);
    fill(d_short,d_short+MAX,INF);
    fill(d_short_square,d_short_square+MAX,INF);
    fill(pre,pre+MAX,0);
    fill(d,d+MAX,INF);
    d[s]=0;
    d_long[s]=0;
    d_short[s]=0;
    while(1)
    {
        int u=-1;
        long long mini=INF;
        for(int i=1;i<=n;i++)
        {
            if(vis[i]==0&&d[i]<mini)
            {
                u=i;
                mini=d[i];
            }
        }
        if(u==-1) break;
        vis[u]=1;
        for(int v=1;v<=n;v++)
        {
            if(G[u][v].cost!=INF&&vis[v]==0)
            {
                if(G[u][v].type==1)
                {
                    long long d1=INF;
                    long long d2=INF;
                    if(d_short[u]!=INF)//如果有小道與源結點相連
                    {
                        //需要處理一種特殊情況,就是大道、小道交錯出現的情況
                        if(pre[u]==0) d1=square(d_short[u]+G[u][v].cost);
                        else d1=d_long[pre[u]]+square(d_short[u]+G[u][v].cost);//可能出現a通過大道與b相連,b通過小道與c相連
                                                                               //c通過小道與d相連的情況
                    }
                    if(d_long[u]!=INF)//如果有大道與源結點相連
                        d2=square(G[u][v].cost)+d_long[u];
                    if(d1<d2)
                    {
                        d_short[v]=min(d_short[v],d_short[u]+G[u][v].cost);//更新結點對應的小道點權
                        d_short_square[v]=min(d1,d_short_square[v]);
                    }
                    else
                    {
                        d_short[v]=min(d_short[v],G[u][v].cost);//由於上一條道路是大道,所以這裡需要從頭開始考慮小道的點權
                        d_short_square[v]=min(d2,d_short_square[v]);
                        pre[v]=u;//記錄當前結點的前驅結點
                    }
                    d[v]=min(d_short_square[v],d_long[v]);
                }
                else//當前道路是大道
                {
                    long long d1=INF;
                    long long d2=INF;
                    if(d_long[u]!=INF)  d1=d_long[u]+G[u][v].cost;
                    if(d_short[u]!=INF) d2=d_short_square[u]+G[u][v].cost;
                    long long mini=min(d1,d2);
                    d_long[v]=min(d_long[v],mini);
                    d[v]=min(d_short_square[v],d_long[v]);
                }
            }
        }
    }
    return;
}

int main()
{
    int n,m;
    int t,a,b;
    long long c;
    //freopen("a.txt","r",stdin);
    scanf("%d %d",&n,&m);
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=n;j++)
        {
            G[i][j].cost=INF;
            G[j][i].cost=INF;
        }
    }
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d%lld",&t,&a,&b,&c);
        if(t==1)//小道
        {
            G[a][b].cost=c;
            G[b][a].cost=c;
            G[a][b].type=1;
            G[b][a].type=1;
        }
        else
        {
            G[a][b].cost=c;
            G[b][a].cost=c;
            G[a][b].type=0;
            G[b][a].type=0;
        }
    }
    Djs(1,n);
    printf("%lld\n",d[n]);
    return 0;
}