NOIP2017 洛谷 逛公園

2021-09-27 13:05:42 字數 3394 閱讀 8856

初見安~這個本狸咕了4個月的題終於寫出來了qaq!!!這裡是傳送門:洛谷p3953 逛公園

策策每天都會去逛公園,他總是從1號點進去,從nn號點出來。

策策喜歡新鮮的事物,它不希望有兩天逛公園的路線完全一樣,同時策策還是乙個 特別熱愛學習的好孩子,它不希望每天在逛公園這件事上花費太多的時間。如果1號點 到nn號點的最短路長為dd,那麼策策只會喜歡長度不超過d + kd+k的路線。

策策同學想知道總共有多少條滿足條件的路線,你能幫幫它嗎?

為避免輸出過大,答案對pp取模。

如果有無窮多條合法的路線,請輸出-1−1。

第一行包含乙個整數 tt, 代表資料組數。

接下來tt組資料,對於每組資料: 第一行包含四個整數 n,m,k,pn,m,k,p,每兩個整數之間用乙個空格隔開。

接下來mm行,每行三個整數a_i,b_i,c_iai​,bi​,ci​,代表編號為a_i,b_iai​,bi​的點之間有一條權值為 c_ici​的有向邊,每兩個整數之間用乙個空格隔開。

輸出檔案包含 tt 行,每行乙個整數代表答案。

2

5 7 2 10

1 2 1

2 4 0

4 5 2

2 3 2

3 4 1

3 5 2

1 5 3

2 2 0 10

1 2 0

2 1 0

3

-1

【樣例解釋1】

對於第一組資料,最短路為 33。 1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5 為 33 條合法路徑。

【測試資料與約定】

對於不同的測試點,我們約定各種引數的規模不會超過如下

測試點編號

ttnn

mmkk

是否有0邊15

5100否

251000

20000否

351000

200050否

451000

200050否

551000

200050否

651000

200050是

75100000

2000000否

83100000

20000050否

93100000

20000050是

103100000

20000050是

對於 100%的資料,

四個月前看吧,只能寫個20分的最短路騙分……現在來看,還是可以想到dp的狀態和大致的轉移過程了。我是不是很棒!!!!!!!!!!!!!!!!【然而最後還是看了別人的題解quq】

就沿著我的思路走走吧——最短路首先是要求一遍的。然後考慮統計路徑數。如果是問的最短路的路徑數,我們的處理方式很明顯是:建反圖,跑最短路,然後再沿著正圖去累加答案計數。【因為是有向圖就只有建兩個圖了……】建反圖是因為要考慮某邊對到點n的距離的影響而非到點1的影響。

那麼多了乙個長度<=k的限制呢?k只有50,很明顯我們可以寫乙個。累計答案的過程因為要遍歷整個圖,我們又有k+1種情況,所以就順勢用記憶化搜尋來統計dp的值。

怎麼統計?因為k的值不確定很麻煩,那麼我們就先確定k的值再去dfs。假設我們到了點u,要去點v,現在統計的路徑還可以比最短路多left,那麼v轉移過來的狀態就只能多

因為我們dis存的是到n的最短路,如果走這條邊,那麼相比最短路,路徑長度就會多出

至此,我們就已經大致講完了記憶化搜素的部分。接下來是什麼時候無解呢——很明顯是出現0環。0環怎麼判斷?看0環對我們記搜過程的影響吧——如果我們走了乙個環,回來過後還會繼續累加答案對吧?這時候的left會和第一次進來時的left一模一樣【0環嘛,走了一圈為0的邊權。】那我們記錄一下第一次進來時的left,看什麼時候相同了,是不是就可以判斷是出現0環了?當然可以!!!!!!!!

但是如果要在dfs的過程中判環的話,我們就不能一開始就把

還有乙個細節就是——的情況是存在的。如果=0的時候還繼續搜下去了,就會tle乙個點。quq

以上兩點會在**中強調。

所以這個題就結束了。quq

上**——【**有參考別的博文】

#include#include#include#include#include#include#define maxn 100005

using namespace std;

typedef long long ll;

int read()

while(isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar();

return x * f;

}struct edge e[maxn << 1], e2[maxn << 1];

int head[maxn], k = 0, head2[maxn], k2 = 0;

void add(int u, int v, int w) ; head[u] = k++;}//正圖

void add2(int u, int v, int w) ; head2[u] = k2++;}//反圖

int n, m, t, k, p;

int dp[maxn][55];

int dis[maxn];

struct node

};priority_queueq;

void dij() );

while(q.size()) );

}} }

}bool flag = false;

int zc[maxn];//zero_circle,0環標記

int dfs(int u, int left)

if(dp[u][left] >= 0) return dp[u][left];// very significant!!!

zc[u] = left;//進入環

int sum = 0;

for(int i = head[u]; ~i; i = e[i].nxt)

zc[u] = -1;//退出環

if(u == n && left == 0) sum = 1;// very important!!!

return dp[u][left] = sum;

}signed main()

if(flag) puts("-1");

else printf("%d\n", ans);

} return 0;

}

迎評:)

——end——

比賽 NOIP2017 逛公園

考試的時候靈光一閃,瞬間推出dp方程,但是不知道怎麼判 1,然後?然後就炸了。後來發現,我只要把拓撲和dp分開,中間加乙個判斷,就ac了,可惜。看這道題,我們首先來想有哪些情況是 1 只要有零環在滿足題目要求的路徑上,那麼這條路徑就可以不停地走,於是就 1了。如何判有沒有零環呢?機械化地兩遍不同方向...

NOIp2017 逛公園 dp 記搜

給定乙個有向圖,起點為 1 終點為 n 求和最短路相差不超過 k 的路徑數量.有 0 邊.如果有無數條,則輸出 1 n leq 10 5,k leq 50 首先,有無數條邊的情況一定是在與最短路相差不超過 k 的一條路上有 0 環.先不考慮 0 邊和 0 環,get 70pts 做法 先跑乙個最短路...

NOIP 2017 逛公園 最短路 dp

題意 求出 從 1 到 n 的路徑長度小於等於最短路 k 的路徑個數 分析 首先觀察資料特點 30 的資料 k 0 且沒有 0 邊,等同於最短路計數 70 的資料沒有 0 邊,那麼就是相當於沒有 0 環 100 的資料 k le 50 首先考慮第一檔 顯然就是乙個最短路徑計數,是乙個非常經典的問題,...