题解 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\,])
\]
对于阶段,可以这样来枚举:
-
枚举每种状态 \(i\) :\((1001110,1001111,1110101……)\) ;
-
枚举当前点 \(j\) ;
-
枚举到达 \(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;
}