NOIP 2017 逛公園(最短路 記憶化搜尋)

2021-09-30 16:32:10 字數 1377 閱讀 3417

肯定要先跑一次最短路

題目中的k 相當於允許我們走k距離的「冤枉路」

回想之前有些題是如何判斷哪些邊是屬於最短路上的 當dis[now]+edge[u].val==dis[vis] 這條邊就在最短路上

類似的 我們可以得出 dis[now]+edge[u].val-dis[vis]就是這一次走的「冤枉路」的長度

到這個地方搜尋的策略已經很明顯了 dfs(now,remain)表示當前當前點為now 還剩remain的冤枉路可以走

邊界條件:remain<0

然後發現這玩意兒不用標記vis陣列 因為就算有環 remain會一直減下去直到<0 還可以記憶化一下

不過無窮多的情況腫麼判?

可以這樣想 為什麼資料會給你有沒有0邊?

回憶最短路計數就會問你有沒有無窮多條滿足要求的路 這種情況只有可能是有0環存在

在這道題裡判0環異常容易 假如進入了0環 那肯定會繞了一圈後 又回到當前點 且remain不變

因此標記一下就好

另外 還有乙個坑點 這是有向圖 很有可能有些點無法到達終點

因此還要反向搜出那些不能到達的

#include#define n 100005

#define m 200005

#define inf 0x3f3f3f3f

using namespace std;

templateinline void read(t &x)

struct edge

edge[2*m];

struct node };

int n,m,k,p,tot,first[n],dis[n];

inline void addedge(int x,int y,int z)

vectorres[n];

typedef pairpair;

bool visit[n],able[n];

void dijkstra(int s)

{ memset(dis,0x3f,sizeof(dis));

memset(visit,false,sizeof(visit));

priority_queue,greater> heap;

heap.push(make_pair(0,s)); dis[s]=0;

while(!heap.empty())

{int now=heap.top().second;

heap.pop();

if(visit[now]) continue;

visit[now]=true;

for(int u=first[now];u;u=edge[u].next)

{int vis=edge[u].to;

if(dis[now]+edge[u].val

NOIP 2017 逛公園 最短路 dp

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

NOIp2017 逛公園 dp 記搜

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

比賽 NOIP2017 逛公園

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