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.

76 lines
3.2 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 N = 15;
const int INF = 0x01010101;
int g[N][N]; // 图的邻接矩阵
int n, m; // n个节点m条边
vector<int> p[N]; // 第一维:哪一行;第二维:此行第几个是哪个点
bool st[N]; // 每个节点是否已使用
int res = INF; // 代价最小值,预求最小,先设最大
int micost[N]; // 每个点最小的代价,相对前一个贪心+暴搜这个采用了一个估值函数用于A*寻路
// 现在第u层讨论k号节点总共用了cnt个点现在这棵树价值sum剩余点的总最小估值代价
void dfs(int u, int k, int cnt, int sum, int r) {
// 最优性剪枝 !!!最重要!!!只要现阶段不是最小的了就没有继续的必要了
// 假设本层u把剩余的所有节点全部覆盖那么最小代价根据定义就是r*u,再加上以前积累的sum
// 总代价就将是sum+r*u,如果此最小代价仍然高于目前取得的小值,那么,此路径无用
if (sum + r * u >= res) return;
if (p[u - 1].size() == 0) return; // 上一层没有选入点(上层为空),树不可能继续构建,该可能不合法,直接跳过
if (cnt == n) {
res = min(sum, res); // 所有点都已经被构建进树中,更新答案,结束这种可能
return;
}
if (k > n) {
dfs(u + 1, 1, cnt, sum, r); // 该层所有点都讨论过一遍,继续下一层
return;
}
if (st[k]) {
dfs(u, k + 1, cnt, sum, r); // 该点已用,直接讨论下一个点
return;
}
// 选用此点可能1
int cost = INF; // 找到该点与上层的最小联系(贪心)
for (int i = 0; i < p[u - 1].size(); i++) // 若与上层所有点不连通则mini是INF,会被最优性剪枝减去
cost = min(cost, g[p[u - 1][i]][k]);
st[k] = 1; // 能算到这里,该点没用过,用下试试
p[u].push_back(k);
dfs(u, k + 1, cnt + 1, sum + cost * u, r - micost[k]);
p[u].pop_back();
st[k] = 0; // 回溯
// 不用此点可能2
dfs(u, k + 1, cnt, sum, r);
}
int main() {
memset(g, 0x3f, sizeof g);
memset(micost, 1, sizeof micost);
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); // 无向图双向赋值,只取最小值
// 记录接入a,b的最少代价,用于估值
micost[a] = min(micost[a], c);
micost[b] = min(micost[b], c);
}
// 整体最小估值
int r = 0;
for (int i = 1; i <= n; i++) r += micost[i];
for (int i = 1; i <= n; i++) { // 每个点都当一次根
st[i] = 1; // 点已用
p[0].push_back(i); // 根看做第0层
dfs(1, 1, 1, 0, r - micost[i]); // 从第一层开始搜索,考查第1个节点目前使用了节点个数为1总代价为0最小估值为sum-micost[i]
p[0].pop_back();
st[i] = 0; // 以该点为根的数搜索完毕
}
cout << res << endl;
return 0;
}