You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

72 lines
2.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x01010101; // 这个上限有点意思,需要仔细思考
const int N = 15; // 点的个数上限 
int g[N][N]; // 记录边,就是地图
int n, m; // n个节点m条边
vector<int> p[N]; // 第一维:哪一行;第二维:此行第几个是哪个点
bool st[N]; // 每个点是否被用过
int res = INF; // 结果
/*
* u:第u层
* k:正在枚举第几号节点尝试将这个节点填充到u层中去
* cnt:已经使用了cnt个点
* sum:目前生成树最小价值
*/
void dfs(int u, int k, int cnt, int sum) {
if (sum >= res) return; // 走一半就比最优值大,剪枝
if (p[u - 1].size() == 0) return; // 上一层没有选入点(上层为空),树无法继续构建,递归出口
if (cnt == n) { // 所有点都已经被构建到树中,结果有资格参选最优解
res = sum; // 因为上面有最优剪枝,大的都被提前返回了,到达这里时肯定是更小的值
return;
}
if (k > n) { // 该层所有点都讨论过一遍,继续下一层,回到1号节点处开始
dfs(u + 1, 1, cnt, sum);
return;
}
// 如果u层k号点被标识为用过了
if (st[k]) { // 该点已用,继续讨论下一个节点
dfs(u, k + 1, cnt, sum);
return;
}
int cost = INF; // 找到该点与上层的最小联系
for (int i = 0; i < p[u - 1].size(); i++) // 若没有联系即与上层所有点不连通则mini是INF,会被最优性剪枝减去
cost = min(cost, g[p[u - 1][i]][k]); // 上一行的每个节点如果与k号节点的边相连并且权值最小的话更新cost
// 找到了上一层到u层使得k点点亮的最小代价值
// 选用此点可能1
st[k] = 1; // 标识k点已使用
p[u].push_back(k);
dfs(u, k + 1, cnt + 1, sum + cost * u);
p[u].pop_back();
st[k] = 0; // 回溯
// 不用此点可能2
dfs(u, k + 1, cnt, sum);
}
int main() {
memset(g, 0x3f, sizeof g); // 数组初始化
scanf("%d %d", &n, &m);
while (m--) {
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
g[a][b] = g[b][a] = min(g[a][b], c); // 无向图
}
for (int i = 1; i <= n; i++) { // 每个点都当一次根
st[i] = 1; // i点已用
p[0].push_back(i); // 根是第0层,第1个放的是i
dfs(1, 1, 1, 0); // 从第一层,第一个节点,已经使用了一个节点(根),现在的代价是0
p[0].pop_back(); // 回溯
st[i] = 0; // 回溯
}
cout << res << endl;
return 0;
}