【USACO14FEB】路障Roadblock Dijkstra+路徑記錄

題目描述

每天早晨,FJ從家中穿過農場走到牛棚。農場由 N 塊農田組成,農田通過 M 條雙向道路連接,每條路有一定長度。FJ 的房子在 1 號田,牛棚在 N 號田。沒有兩塊田被多條道路連接,以適當的路徑順序總是能在農場任意一對田間行走。當FZ從一塊田走到另一塊時,總是以總路長最短的道路順序來走。

FJ 的牛呢,總是不安好心,決定干擾他每天早晨的計劃。它們在 M 條路的某一條上安放一疊稻草堆,使這條路的長度加倍。牛希望選擇一條路干擾使得FJ 從家到牛棚的路長增加最多。它們請你設計並告訴它們最大增量是多少。

輸入輸出格式

輸入格式:
第 1 行:兩個整數 N, M。

第 2 到 M+1 行:第 i+1 行包含三個整數 A_i, B_i, L_i,A_i 和 B_i 表示道路 i 連接的田的編號,L_i 表示路長。

輸出格式:
第 1 行:一個整數,表示通過使某條路加倍而得到的最大增量。

輸入輸出樣例

輸入樣例#1:
5 7
2 1 5
1 3 1
3 2 8
3 5 7
3 4 3
2 4 7
4 5 2
輸出樣例#1:
2
說明

【樣例說明】

若使 3 和 4 之間的道路長加倍,最短路將由 1-3-4-5 變爲 1-3-5。

【數據規模和約定】

對於 30%的數據,N <= 70,M <= 1,500。

對於 100%的數據,1 <= N <= 100,1 <= M <= 5,000,1 <= L_i <= 1,000,000。

題解:、
暴力做法:枚舉每條邊,將邊權*2,跑一遍dij最短路,更新答案。
正解:首先跑一遍dij求出最短路,那麼如果將除了該最短路上的路徑的其他邊翻倍的話,那麼再次dij時得到的一定還是第一遍求出的最短路。所以正解是枚舉最短路上的每一條邊,將其翻倍,然後跑一遍dij更新答案。

代碼:

#include<cmath>
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,m,pre[25005],k,ans;
int minn,c[255],maxx=0x7fffffff,anss=-1;
int f[255][255];
bool flag[255],pd[255][255];
int get()
{
    int x=0,p=1;
    char c;
    c=getchar();
    while (c<'0'||c>'9') {if (c=='-') p=-1;c=getchar();}
    while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    return x*p;
}
int main()
{   
    int I,x,y,z,i,j;
    n=get();m=get();
    memset(f,127/3,sizeof(f));
    for (i=1;i<=m;i++)
    {
        x=get();y=get();z=get();
        f[x][y]=f[y][x]=z;
        pd[x][y]=pd[y][x]=1;
    }
    memset(c,127/3,sizeof(c));
    memset(flag,false,sizeof(flag));
    c[1]=0;
    for (i=1;i<=n;i++)
    {
        minn=maxx;
        k=0;
        for (j=1;j<=n;j++)
            if ((!flag[j])&&(c[j]<minn))
            {
                minn=c[j];
                k=j;
            }
        if (k==0) break;
        flag[k]=true;
        for (j=1;j<=n;j++)
        {
            if (c[k]+f[k][j]<c[j])
            {
                c[j]=c[k]+f[k][j];
                pre[j]=k;
            }   
        }
    }
    ans=c[n];
    pre[1]=0;
    for (I=n;pre[I];I=pre[I])
    {
        f[I][pre[I]]*=2;
        f[pre[I]][I]*=2;
        memset(c,127/3,sizeof(c));
        memset(flag,false,sizeof(flag));
        c[1]=0;
        for (i=1;i<=n;i++)
        {
            minn=maxx;
            k=0;
            for (j=1;j<=n;j++)
                if ((!flag[j])&&(c[j]<minn))
                {
                    minn=c[j];
                    k=j;
                }
            if (k==0) break;
            flag[k]=true;
            for (j=1;j<=n;j++)
            {
                if (c[k]+f[k][j]<c[j])
                    c[j]=c[k]+f[k][j];
            }
        }
        anss=max(anss,c[n]-ans);
        f[I][pre[I]]/=2;
        f[pre[I]][I]/=2;
    }
    printf("%d",anss);
    return 0;
}
發佈了79 篇原創文章 · 獲贊 32 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章