题面网上肯定找得到,不贴了……
仍然填大坑ing……
当初在考场上看到了此题,由于发现 k ≤ 50 k\le50 k≤50,所以自然要在 k k k上搞事情。设 f [ i ] [ j ] f[i][j] f[i][j]表示到达i点此时的路径总长度比最长路长j的题解,初始最短路求一趟,然后转移……转移……我又写了个spfa神奇转移骗走60分……
这道题可以考虑拓扑+DP转移,然而也可以记忆化DFS转移,由于记忆化DFS转移方便,所以各位可以在网上找有关DP+拓扑的解法。
当初转移的时候是
f [ s o n [ j ] ] [ k + w + d s t [ x ] − d s t [ s o n [ j ] ] ] + = f [ x ] [ k ] f[son[j]][k+w+dst[x]-dst[son[j]]]+=f[x][k] f[son[j]][k+w+dst[x]−dst[son[j]]]+=f[x][k]
但其实可以反过来,反向建图一波。
f [ x ] [ k ] = ∑ f [ s o n [ j ] ] [ k − w [ j ] + d s t [ x ] − d s t [ s o n [ j ] ] ] f[x][k]=\sum f[son[j]][k-w[j]+dst[x]-dst[son[j]]] f[x][k]=∑f[son[j]][k−w[j]+dst[x]−dst[son[j]]]
然后判断无数个解,即图中存在0环,其实在记忆化搜索的过程中某个状态出现了两次就说明出现了 0 环。
#include
#include
#include
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]]