https://www.luogu.com.cn/problem/P3959
- 分别枚举每一个起点,因为后来的选择不会影响到前面的选择,满足无后效性,同时局部最优可以扩展到全局最优,满足最优子结构性质,可以使用 D P DP DP,使用常规状态压缩办法,枚举接下来的每一个可能的位置,然后记录状态进行 d f s dfs dfs,同时需要记录当前经过的宝藏屋的数量,如果需要更新,则更新,同时继续搜索,最后取所有解的最小值
- 这里图比较小,要用邻接矩阵,不要用链式前向星,边太多了,会超时
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
int edge[15][15];
int f[1 << 15];
int dis[15];
int n;
void dfs(int s){
for(int i=1;i<=n;i++){
if(s & (1 << (i - 1))){
for(int j=1;j<=n;j++){
if(edge[i][j] == INF || i == j) continue;
if(f[s | (1 << (j - 1))] > f[s] + dis[i] * edge[i][j]){
int tmp = dis[j];
dis[j] = dis[i] + 1;
f[s | (1 << (j - 1))] = f[s] + dis[i] * edge[i][j];
dfs(s | (1 << (j - 1)));
dis[j] = tmp;
}
}
}
}
}
int main(){
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
int m, u, v, w;
cin >> n >> m;
memset(edge, 0x3f, sizeof edge);
for(int i=1;i<=m;i++){
cin >> u >> v >> w;
edge[u][v] = edge[v][u] = min(edge[u][v], w);
}
int ans = INF;
for(int i=1;i<=n;i++){
memset(dis, 0x3f, sizeof dis);
memset(f, 0x3f, sizeof f);
dis[i] = 1;
f[1 << (i - 1)] = 0;
dfs(1 << (i - 1));
ans = min(f[(1 << n) - 1], ans);
}
cout << ans;
return 0;
}