洛谷P3959:https://www.luogu.org/problemnew/show/P3959
前言
NOIP2017时还很弱(现在也很弱
看出来是DP 但是并不会状压DP
现在看来思路并不复杂 只是存状态有点难想到
思路
因为n最大为12
所以可以想到是状压
因为n<=12 所以可以用邻接矩阵存下图
枚举每个点作为起点开始DFS
注意每次DFS的初始化和赋值问题即可
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define INF 1e9+7
int n,m,ans=INF;
int f[],h[],dis[],map[][];//dis为题目中的k 即经过了几个宝藏
bool vis[][];
void dfs(int s)
{
for(int i=;i<=n;i++)
{
if(s&(<<(i-)))//寻找已经挖通的宝藏
for(int j=;j<=n;j++)//枚举下一个宝藏
{
if(!(s&(<<(j-)))&&vis[i][j]&&f[<<(j-)|s]>f[s]+dis[i]*map[i][j])
{//如果没有挖过j 且i与j之间有路径 且有一个更优解
int k=dis[j];//记录原dis方便后面回溯
dis[j]=dis[i]+;//记录新的dis
f[<<(j-)|s]=f[s]+dis[i]*map[i][j];//更新更优解
dfs(s|<<(j-));
dis[j]=k;//回溯
}
}
}
}
int main()
{
cin>>n>>m;
memset(map,INF,sizeof(map));//矩阵赋值最大值
for(int i=;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
if(z<map[x][y])//取最小的一条路
{
map[x][y]=z;
map[y][x]=z;
vis[x][y]=;//判断是否存在路径
vis[y][x]=;
}
}
for(int i=;i<=n;i++)//枚举每个点为起点
{
memset(dis,INF,sizeof(dis));//初始化
memset(f,INF,sizeof(f));
dis[i]=;//起点经过的点有1个
f[<<(i-)]=;//当前状态的最小值
dfs(<<(i-));//搜索
ans=min(ans,f[(<<n)-]);//状态满的时候取最小值
}
cout<<ans;
}