【NOIP 2017 提高組】逛公園
【題目】
題目描述:
策策同學特別喜歡逛公園。公園可以看成一張 個點 條邊構成的有向圖,且沒有自環和重邊。其中 號點是公園的入口, 號點是公園的出口,每條邊有一個非負權值,代表策策經過這條邊所要花的時間。
策策每天都會去逛公園,他總是從 號點進去,從 號點出來。
策策喜歡新鮮的事物,他不希望有兩天逛公園的路線完全一樣,同時策策還是一個特別熱愛學習的好孩子,他不希望每天在逛公園這件事上花費太多的時間。如果 號點到 號點的最短路長為 ,那麼策策只會喜歡長度不超過 的路線。
策策同學想知道總共有多少條滿足條件的路線,你能幫幫他嗎?
為避免輸出過大,答案對 取模。
如果有無窮多條合法的路線,請輸出 。
輸入格式:
第一行包含一個整數 ,代表資料組數。
接下來 組資料,對於每組資料:
第一行包含四個整數 ,,,,每兩個整數之間用一個空格隔開。
接下來 行,每行三個整數 ,,,代表編號為 , 的點之間有一條權值為 的有向邊,每兩個整數之間用一個空格隔開。
輸出格式:
輸出檔案包含 行,每行一個整數代表答案。
樣例資料:
輸入 2 5 7 2 10 1 2 1 2 4 0 4 5 2 2 3 2 3 4 1 3 5 2 1 5 3 2 2 0 10 1 2 0 2 1 0
輸出 3 -1
備註:
【輸入輸出樣例1說明】 對於第一組資料,最短路為 。 ,, 為 條合法路徑。
【資料規模與約定】 對於不同的測試點,我們約定各種引數的規模不會超過如下 對於 的資料,;;。 資料保證:至少存在一條合法的路線。
【分析】
:
這部分的分應該是比較容易得到的吧
,轉換一下題目意思就是統計最短路個數,由於 是沒有 邊的,所以還不用判斷是否有無窮中路線
不過要注意的是一定要有 陣列啊,不然會重複計算的,就錯了(被坑了無數次了)
沒有 邊:
這一部分分是用 來做的
首先肯定還是要求最短路(這應該是廢話)
定義 為 到 的最短路, 為比 多 的方案數
現在考慮怎麼轉移,假如現在 可以到 ,邊權為 ,並且是從 轉移到
那麼容易得到 ,移項得 ,那方程就是:
(當然如果發現 了直接跳過就好了)
實際操作的時候用記憶化搜尋實現就可以了
:
現在考慮加上 邊該怎麼辦
其實也比較簡單,只用再記錄一個 表示 這個狀態出現過沒有
如果存在環,從 開始搜尋的話(狀態是 ),就會再次搜到 (注意是搜尋到 ,不是回溯到 )
那麼假設這個環上的其他點為 ,邊權為 ,假如回到 的狀態依舊是 ,就說明 ( 會互相抵消掉),就是 環,這時就輸出
【程式碼】
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define K 55
#define N 100005
#define M 500005
using namespace std;
int n,m,k,p,t1,t2,flag;
int d[N],f[N][K],vis[N][K];
int first[N],v[M],w[M],nxt[M];
int First[N],V[M],W[M],Nxt[M];
priority_queue<pair<int,int> >q;
void add(int x,int y,int z) {nxt[++t1]=first[x];first[x]=t1;v[t1]=y;w[t1]=z;}
void Add(int x,int y,int z) {Nxt[++t2]=First[x];First[x]=t2;V[t2]=y;W[t2]=z;}
void init()
{
t1=t2=flag=0;
memset(f,-1,sizeof(f));
memset(first,0,sizeof(first));
memset(First,0,sizeof(First));
}
void dijkstra(int s)
{
int x,y,i;
memset(d,127/3,sizeof(d));
q.push(make_pair(0,s));d[s]=0;
while(!q.empty())
{
x=q.top().second;q.pop();
for(i=first[x];i;i=nxt[i])
{
y=v[i];
if(d[y]>d[x]+w[i])
{
d[y]=d[x]+w[i];
q.push(make_pair(-d[y],y));
}
}
}
}
int dfs(int now,int val)
{
if(~f[now][val]) return f[now][val];
int i,to,num;f[now][val]=0,vis[now][val]=1;
for(i=First[now];i;i=Nxt[i])
{
to=V[i];
num=d[now]-d[to]+val-W[i];
if(num<0) continue;
if(vis[to][num]) flag=1;
f[now][val]=(f[now][val]+dfs(to,num))%p;
}
vis[now][val]=0;
return f[now][val];
}
int main()
{
int x,y,z,i,T