洛谷P3953 逛公園
阿新 • • 發佈:2019-01-31
超過 直接 事物 pla 最短 同時 return getchar() 長度 取模。
如果有無窮多條合法的路線,請輸出\(-1\)。 為\(i\)號節點到\(N\)號節點的最短路徑長度。
\(F_{i,j}\)表示第\(i\)號節點在路線長度為\(d+k-j\)時的路線條數,或者說是第\(i\)號節點還可以浪費\(j\)個單位距離時的路線條數。
那麽轉移方程如下:\[F_{i,j}=\sum_{k \in \{ k| (i,k) \in E \}}{F_{k,j+Dis_i-(Dis_k+W_{i,k})}}\]
因此,本問題也就可以用記憶化搜索求了
再考慮有無數解的情況,很顯然,當且僅當出現零環的時候回有無數解。
也就是說,我們只要在記憶化搜索之前找一下有沒有零環,有的話直接輸出\(-1\)沒有的話在做記憶化搜索
可以用tarjan縮點判斷零環
先將圖中所有長度大於\(0\) 的邊都去掉,然後跑tarjan,如果縮出來的強連通分量中有頂點數大於\(1\)的,那麽就說明有零環。
洛谷P3953 逛公園
題目描述
策策同學特別喜歡逛公園。公園可以看成一張\(N\)個點\(M\)條邊構成的有向圖,且沒有自環和重邊。其中1號點是公園的入口,\(N\)號點是公園的出口,每條邊有一個非負權值, 代表策策經過這條邊所要花的時間。
策策每天都會去逛公園,他總是從1號點進去,從\(N\)號點出來。
策策喜歡新鮮的事物,它不希望有兩天逛公園的路線完全一樣,同時策策還是一個 特別熱愛學習的好孩子,它不希望每天在逛公園這件事上花費太多的時間。如果1號點 到\(N\)號點的最短路長為\(d\),那麽策策只會喜歡長度不超過\(d+K\)的路線。
策策同學想知道總共有多少條滿足條件的路線,你能幫幫它嗎?
為避免輸出過大,答案對\(P\)
如果有無窮多條合法的路線,請輸出\(-1\)。
輸入輸出格式
輸入格式:
第一行包含一個整數 \(T\), 代表數據組數。
接下來\(T\)組數據,對於每組數據: 第一行包含四個整數 \(N,M,K,P\),每兩個整數之間用一個空格隔開。
接下來\(M\)行,每行三個整數\(a_i,b_i,c_i\),代表編號為\(a_i,b_i\)?的點之間有一條權值為 \(c_i\)?的有向邊,每兩個整數之間用一個空格隔開。
輸出格式:
輸出文件包含 \(T\) 行,每行一個整數代表答案。
思路
記憶化搜索
首先從\(N\)開始反向求一遍最短路,這樣就得到了每一個點到\(N\)號節點的最短路徑長度,記\(Dis_i\)
\(F_{i,j}\)表示第\(i\)號節點在路線長度為\(d+k-j\)時的路線條數,或者說是第\(i\)號節點還可以浪費\(j\)個單位距離時的路線條數。
那麽轉移方程如下:\[F_{i,j}=\sum_{k \in \{ k| (i,k) \in E \}}{F_{k,j+Dis_i-(Dis_k+W_{i,k})}}\]
因此,本問題也就可以用記憶化搜索求了
再考慮有無數解的情況,很顯然,當且僅當出現零環的時候回有無數解。
也就是說,我們只要在記憶化搜索之前找一下有沒有零環,有的話直接輸出\(-1\)沒有的話在做記憶化搜索
可以用tarjan縮點判斷零環
先將圖中所有長度大於\(0\)
CODE
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std;
#define MAXN 100010
#define MAXM 200010
struct R{
int id,dis;
R(){}
R(int id,int dis):id(id),dis(dis){}
bool operator < (const R &a) const {
return dis>a.dis;
}
};
struct Node{
int u,v,w;
Node(){}
Node(int u,int v,int w):u(u),v(v),w(w){};
}p[MAXM],revp[MAXM];
int head[MAXN],revhead[MAXN],Next[MAXM],revNext[MAXM],dis[MAXN],cnt[MAXN][55],dfn[MAXN],low[MAXN],color[MAXN];
bool vis[MAXN];
int i,j,k,m,n,x,y,u,v,w,tot,revtot,times,colnum,t,r,mod,mindis;
stack<int> mstack;
char readc;
bool flag;
void read(int &n){
while((readc=getchar())<48||readc>57);
n=readc-48;
while((readc=getchar())>=48&&readc<=57) n=n*10+readc-48;
}
void addNode(int u,int v,int w){
p[++tot]=Node(u,v,w);
Next[tot]=head[u],head[u]=tot;
revp[++revtot]=Node(v,u,w);
revNext[revtot]=revhead[v],revhead[v]=revtot;
}
bool relax(int u,int v,int w){
if(dis[u]+w<dis[v]){
dis[v]=dis[u]+w;
return true;
}
return false;
}
void tarjan(int src){
low[src]=dfn[src]=++times;
vis[src]=true;
mstack.push(src);
for(int i=head[src];i+1;i=Next[i]){
if(p[i].w) continue;
if(!dfn[p[i].v]){
tarjan(p[i].v);
low[src]=min(low[src],low[p[i].v]);
}else{
if(vis[p[i].v]) low[src]=min(low[src],dfn[p[i].v]);
}
}
if(low[src]==dfn[src]){
int tmp;
colnum++;
do{
tmp=mstack.top(); mstack.pop();
vis[tmp]=false;
color[colnum]++;
}while(tmp!=src);
}
}
void dijkstra(int src){
memset(dis,0x3f,sizeof(dis));
priority_queue<R> mque;
dis[src]=0;
mque.push(R(src,0));
while(!mque.empty()){
R tmp=mque.top(); mque.pop();
if(tmp.dis>dis[tmp.id]) continue;
for(int i=revhead[tmp.id];i+1;i=revNext[i])
if(relax(revp[i].u,revp[i].v,revp[i].w)){
mque.push(R(revp[i].v,dis[revp[i].v]));
}
}
}
int dfs(int src,int cost){
if(cnt[src][cost]+1) return cnt[src][cost];
cnt[src][cost]=0;
if(src==n) cnt[src][cost]++;
for(int i=head[src];i+1;i=Next[i]){
if((p[i].w+dis[p[i].v])-dis[src]<=cost){
cnt[src][cost]+=dfs(p[i].v,cost+dis[src]-p[i].w-dis[p[i].v]);
cnt[src][cost]%=mod;
}
}
return cnt[src][cost];
}
int main(){
read(t);
for(r=1;r<=t;r++){
memset(head,-1,sizeof(head));
memset(revhead,-1,sizeof(revhead));
memset(vis,0,sizeof(vis));
memset(color,0,sizeof(color));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(cnt,-1,sizeof(cnt));
tot=revtot=-1;
times=colnum=0;
read(n),read(m),read(k),read(mod);
for(i=1;i<=m;i++){
read(u),read(v),read(w);
addNode(u,v,w);
}
for(i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
flag=false;
for(i=1;i<=colnum;i++){
if(color[i]>1){
flag=true;
break;
}
}
if(flag){
printf("-1\n");
continue;
}
dijkstra(n);
mindis=dis[1];
printf("%d\n",dfs(1,k));
}
return 0;
}
洛谷P3953 逛公園