發現 \(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...