初見安~這個本狸咕了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 首先考慮第一檔 顯然就是乙個最短路徑計數,是乙個非常經典的問題,...