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

2 years ago
#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;
}