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...