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

2021-08-25 14:28:20 字數 1711 閱讀 6900

noip2017最難的題目。。。

這裡給一種比較方便理解的做法。

拿到這個題目,啥也不用想,首先得把最短路求出來。然而求最短路時我們要反著建圖,也就是求出n到其他所有點的最短路。為什麼這樣做呢?因為這樣可以避免正向某個點無法到達n點的情況。求出最短路後,我們可以利用動態規劃解決這個問題。首先考慮沒有0邊的情況。我們開乙個二維陣列f[u][know],代表在反向圖中從u到n與從u到n的最短路徑之差等於know的路徑的條數。那麼我們得到結果就是∑f[1][know] (0<=know<=k)。為了求出f,我們可以通過正向圖dfs的方法。接下來我們就需要得到know與轉移後得到新的know值(以下稱為know')的關係。這裡我們可以得到乙個表示式:dis[u]+know=dis[y]+know'+length[i]。只有滿足這個條件時,我們更新得到的新的路徑才對原來的know有貢獻。求和即可。注意初始化f[n][know]為1。對於有0邊的情況,我們開w陣列記錄是否有0邊。如果成功更新就沒有,反之就有,flag=1,返回主函式輸出-1.為了卡過這道題,我們應當用讀入優化,而且還要在主函式裡計算f從0到k的累加值時判斷如果出現flag為true就輸出-1;

#include#include#include#include#include#include#include#define ll long long

#define inf 0x3f3f3f3f

using namespace std;

const int maxn=100010;

const int maxm=200010;

int n,m,t,k,mod;

int head[maxn],nnext[maxm*2],to[maxm*2],length[maxm*2],tot;

int head1[maxn],nnext1[maxm*2],to1[maxm*2],length1[maxm*2],tot1;

int dis[maxn];

bool b[maxn];

int wd[maxn][55],f[maxn][55];

bool flag;

inline int read()

return ans;

}void add(int x,int y,int l)

void add1(int x,int y,int l)

void csh()

void spfa()

}} }

}int dfs(int u,int know)

if(f[u][know]>0) return f[u][know];

wd[u][know]=1;

int sum=0;

for(int i=head[u];i;i=nnext[i])

if(u==n&&know==0) sum=1;

wd[u][know]=0;

f[u][know]=sum;

return sum;

}int main()

spfa();

int ans=0;

memset(wd,0,sizeof(wd));

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

if(flag) cout<<"-1"

} fclose(stdin);

fclose(stdout);

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 逛公園

發現 k leq 50 猜想時間複雜度肯定與 k 有關。令 dis x 表示 1 到 x 的最短路。考慮 dp。先不考慮無限解得情況,設 f x i 表示到達點 x 走過的路程長度為 dis x i 的方案數。那麼 f x i 肯定由一條邊 y,x 轉移而來。設 y,x 的長度為 d 則這條路徑到 ...

洛谷3953 逛公園(DP)

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