解題分析
題面網上肯定找得到,不貼了……
仍然填大坑ing……
當初在考場上看到了此題,由於發現,所以自然要在上搞事情。設表示到達i點此時的路徑總長度比最長路長j的題解,初始最短路求一趟,然後轉移……轉移……我又寫了個spfa神奇轉移騙走60分……
這道題可以考慮拓撲+DP轉移,然而也可以記憶化DFS轉移,由於記憶化DFS轉移方便,所以各位可以在網上找有關DP+拓撲的解法。
當初轉移的時候是
但其實可以反過來,反向建圖一波。
然後判斷無數個解,即圖中存在0環,其實在記憶化搜索的過程中某個狀態出現了兩次就說明出現了 0 環。
示例程序
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100005,maxe=400005;
int n,e,K,tot,tt,tst,ans,dst[maxn],lnk[2][maxn],nxt[maxe],son[maxe],w[maxe],f[maxn][55],que[maxn];
bool vs[maxn][55],vis[maxn],pd;
inline char nc(){
static char buf[100000],*pa=buf,*pb=buf;
return pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),pa==pb)?EOF:*pa++;
}
inline void readi(int &x){
x=0; char ch=nc();
while ('0'>ch||ch>'9') ch=nc();
while ('0'<=ch&&ch<='9'){x=x*10+ch-'0'; ch=nc();}
}
void _add(int t,int x,int y,int z){son[++tot]=y; w[tot]=z; nxt[tot]=lnk[t][x]; lnk[t][x]=tot;}
void _init(){
readi(n); readi(e); readi(K); readi(tt); tot=0;
memset(lnk,0,sizeof(lnk));
for (int i=1,x,y,z;i<=e;i++){
readi(x); readi(y); readi(z);
_add(0,x,y,z); _add(1,y,x,z);
}
}
void _spfa(){
memset(vis,0,sizeof(vis));
memset(dst,63,sizeof(dst));
int hed=0,til=1; que[1]=1; vis[1]=1; dst[1]=0;
while (hed!=til){
hed=(hed+1)%maxn; vis[que[hed]]=0;
for (int j=lnk[0][que[hed]];j;j=nxt[j])
if (dst[son[j]]>dst[que[hed]]+w[j]){
dst[son[j]]=dst[que[hed]]+w[j];
if (!vis[son[j]]){
til=(til+1)%maxn; que[til]=son[j]; vis[son[j]]=1;
if (dst[son[j]]<dst[que[(hed+1)%maxn]]) swap(que[til],que[(hed+1)%maxn]);
}
}
}
}
int _dfs(int x,int k){
if (!pd) return -1; if (f[x][k]!=-1) return f[x][k]; f[x][k]=0; vs[x][k]=1;
for (int j=lnk[1][x];j;j=nxt[j]){
int now=k-(w[j]-dst[x]+dst[son[j]]); if (now<0) continue;
// printf("%d %d %d %d\n",x,son[j],now,k);
if (vs[son[j]][now]){pd=0; return -1;} else f[x][k]=(f[x][k]+_dfs(son[j],now))%tt;
}
vs[x][k]=0; return f[x][k];
}
void _solve(){
_spfa();
memset(f,255,sizeof(f));
memset(vs,0,sizeof(vs));
pd=1; ans=0; f[1][0]=1; _dfs(n,1);
for (int i=0;pd&&i<=K;i++) ans=(ans+_dfs(n,i))%tt;
if (!pd) ans=-1; printf("%d\n",ans);
}
int main()
{
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
readi(tst);
while (tst--){
_init();
_solve();
}
return 0;
}