[记忆化DFS]NOIP2017Day1T3 逛公园 题解

解题分析

题面网上肯定找得到,不贴了……

仍然填大坑ing……

当初在考场上看到了此题,由于发现 k ≤ 50 k\le50 k50,所以自然要在 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]][kw[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]]

你可能感兴趣的:(NOIP题解,一般DP,BFS&DFS)