洛谷P3953 逛公園

2022-06-13 22:30:14 字數 1526 閱讀 1894

發現 \(k\leq 50\),猜想時間複雜度肯定與 \(k\) 有關。

令 \(dis[x]\) 表示 1 到 \(x\) 的最短路。

考慮 dp。先不考慮無限解得情況,設 \(f[x][i]\) 表示到達點 \(x\),走過的路程長度為 \(dis[x]+i\) 的方案數。那麼 \(f[x][i]\) 肯定由一條邊 \((y,x)\) 轉移而來。設 \((y,x)\) 的長度為 \(d\),則這條路徑到 \(y\) 的距離為 \(dis[x]+i-d-dis[y]\)。

所以有\[f[x][i]=\sum_ f[y][dis[x]+i-d-dis[y]]

\]發現有很多狀態會重複計算,套上乙個記憶化即可。

如何判斷是否有無限解?顯然僅當所有合法路徑中存在乙個每條邊的邊權都為 0 的環時才會有無限解。所以在記憶化搜尋中記錄每乙個狀態是否已經在搜尋棧中。如果是,那麼就有無限解。

為什麼呢?因為我們可以證明,對於一條邊 \((y,x)\),從 \(f[y][dis[x]+i-d-dis[y]]\) 轉移到 \(f[x][i]\),那麼一定滿足 \(dis[x]+i-d-dis[y]\leq i\),因為如果 \(dis[x]+i-d-dis[y]>i\),那麼 \(dis[x]>dis[y]+i\),顯然 \(dis[x]\) 就不是 1 到 \(x\) 的最短路。

時間複雜度 \(o(qnk)\)。

#include #define mp make_pair

using namespace std;

typedef long long ll;

const int n=200010,k=55;

int q,n,m,k,ans,mod,tot,head[n],f[n][k],deg[n],dis[n],vis[n],u[n],v[n],d[n];

bool flag[n][k];

struct edge

e[n];

void prework()

void add(int from,int to,int dis)

void dij()

} }}int dp(int x,int p)

if (f[x][p]>=0) return f[x][p];

flag[x][p]=1; f[x][p]=0;

for (int i=head[x];~i;i=e[i].next)

flag[x][p]=0;

if (x==1 && p==0) f[x][p]++;

return f[x][p];

}int main()

dij();

memset(head,-1,sizeof(head));

tot=0;

for (int i=1;i<=m;i++)

add(v[i],u[i],d[i]);

for (int i=0;i<=k;i++)

if (ans<0) printf("-1\n");

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

} return 0;

}

洛谷P3953 逛公園

題目 題解 f u k 表示 dis u,n mindis u,n k的方案數,答案就是 f 1 k f u k f v k mindis v,n mindis u,n w 這樣怎麼判 0環呢?只要在搜尋的時候記錄個 instack 就 ok 了 如果當前的 v還在搜尋的棧中就可以直接返回 1了 不...

題解 洛谷P3953 逛公園(最短路 動態規劃)

noip2017最難的題目。這裡給一種比較方便理解的做法。拿到這個題目,啥也不用想,首先得把最短路求出來。然而求最短路時我們要反著建圖,也就是求出n到其他所有點的最短路。為什麼這樣做呢?因為這樣可以避免正向某個點無法到達n點的情況。求出最短路後,我們可以利用動態規劃解決這個問題。首先考慮沒有0邊的情...

洛谷3953 逛公園(DP)

原題 這道題目看到k特別小,而且k n的空間不會gg,那麼我們考慮乙個dp對吧。設 dp i k 表示到了點i與最短路相差k值的方案數,然後直接記搜 不想用拓撲序列 就可以了。luogu judger enable o2 include include include include include...