题解 P4802 【[CCO 2015]路短最】

P4802 [CCO 2015]路短最

题目大意:

给出一张带权连通图,求 \(0\)\(n-1\) 的最长简单路径的长度。

solution:

看到很小的数据范围 \(2\le n \le 18\) 我们可以考虑状压。设状态 \(f[\,i\,][\,j\,]\) 为当前状态为 \(\,i\,\) 走到 \(\,j\,\) 点的最大路径长。易得状态转移方程为:

\[f[\,i\,][\,j\,]= \text{max}(f[\,i\,][\,j\,],f[\,i\, \bigoplus\,(1\ll j)][\,k\,]+l[\,k\,][\,j\,]) \]

对于阶段,可以这样来枚举:

  1. 枚举每种状态 \(i\)\((1001110,1001111,1110101……)\)

  2. 枚举当前点 \(j\)

  3. 枚举到达 \(j\) 的点 \(k\)

细节处理:

  • 注意 \(l[\,i\,][\,j\,]\) 的顺序,是 \(i->j\)
  • 由于求最大值,我们要将 \(f\) 数组赋个小值,可 \(\text{memset}(f,0xcf,\text{sizeof}(f))\) ,不要太小,以免溢出。

看到这的同学,可以自己去写代码了(tf口吻)

代码
#include<cstdio>
#include<cstring>
using namespace std;
template <class T>
inline T Max(const T x,const T y){return x>y?x:y;}
int f[1<<19][19],l[19][19];
int main(){
	int n,m; scanf("%d%d",&n,&m);
	memset(l,0xcf,sizeof(l));
	int x,y,z;
	while(m--){
		scanf("%d%d%d",&x,&y,&z);
		l[x][y]=z;
	}
	memset(f,0xcf,sizeof(f));
	f[1][0]=0;
	for(int i=1;i<(1<<n);i++)
		for(int j=0;j<n;j++)
			if(i>>j&1)
				for(int k=0;k<n;k++)
					if(i>>k&1&&j!=k)
						f[i][j]=Max(f[i][j],f[i^(1<<j)][k]+l[k][j]);
	int ans=0;
	for(int i=1;i<(1<<n);i++)
		ans=Max(ans,f[i][n-1]);
	printf("%d",ans);
	return 0;
}

End

posted @ 2021-07-29 19:47  Mr_think  阅读(49)  评论(0)    收藏  举报