ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#454 | #80. 「NOIP2017」宝藏 | Pigsyy | 100 | 24ms | 2012kb | C++23 | 3.8kb | 2025-04-24 13:51:45 | 2025-04-24 13:51:47 |
answer
#include <cstdio>
//基础的头文件
#include <algorithm>
//给sort开的头文件
#define INF 1917483645
using namespace std;
int vis[20], lev[20], d[20];
//vis : 已经访问过的点
//lev : 点距离初始点的距离
//d : 通过此点可以达到的点数
int c[20][20], tar[20][20];
//c : 费用
//tar :存下每个点能到的点
/*为什么要特意存下每个点到的点?
答案其实并不困难,加快访问速度*/
int ans = INF, tmp, tot, cnt, n, m, p;
//ans : 最终的答案
//tmp : 最优解剪枝用
//tot : dfs储存中间答案的用具
//cnt :现在已经访问过的点数
//n : 点数
//m : 边数
//p : sort用品
inline bool cmp(int a, int b) {
return c[p][a] < c[p][b];
//按照费用给每个点能到的点排序
}
inline void dfs(int num, int node) {
for (int i = num; i <= cnt; i ++) {
//由第几个被访问的点来扩展
if (tot + tmp * lev[vis[i]] >= ans)
return;
//最优性剪枝,如果当前解加上理论最小的费用都比中途的答案高
//那么这次搜索一定不是最优解
for (int j = node; j <= d[vis[i]]; j ++)
//下一步扩展谁
if (!lev[tar[vis[i]][j]]) { //用lev同时充当标记,有lev代表已访问
cnt ++; //多添加一个点
vis[cnt] = tar[vis[i]][j]; //记录这个点
tmp -= c[vis[cnt]][tar[vis[cnt]][1]]; //理论最小的更新
tot += c[vis[i]][vis[cnt]] * lev[vis[i]]; //加上当前的影响
lev[vis[cnt]] = lev[vis[i]] + 1; //因为从vis[i]拓展,故lev一定为其 + 1
dfs(i, j + 1); //继续从i枚举, 注意到tar[i][1 ~ j]已全部访问,下一次从j + 1尝试访问
tot -= c[vis[i]][vis[cnt]] * lev[vis[i]]; //回溯
lev[vis[cnt]] = 0; //回溯
tmp += c[vis[cnt]][tar[vis[cnt]][1]]; //回溯
cnt --; //回溯
}
node = 1; //剪枝别剪错了,i枚举玩下次还要从1枚举
}
if (cnt == n) { //已经访问了n个点,更新答案
if (tot < ans)
ans = tot;
return;
}
}
int main() {
int u, v, w;
scanf("%d%d", &n, &m); //读入n, m
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
c[i][j] = INF; //初始赋无限大,方便后面的操作
for (int i = 1; i <= m; i ++) {
scanf("%d%d%d", &u, &v, &w); //这个w先暂时存起来
//因为发现m = 1000 远> n * n,所以要剪掉一些边
if (c[u][v] < w)
continue; //w不能更新c[u][v]
if (c[u][v] == INF) //第一次更新c[u][v],统计u,v的出度
tar[u][++ d[u]] = v, tar[v][++ d[v]] = u;
c[u][v] = c[v][u] = w;
}
for (int i = 1; i <= n; i ++) {
p = i; //sort排序cmp
sort(tar[i] + 1, tar[i] + 1 + d[i], cmp);
tmp += c[i][tar[i][1]]; //因为每个点总要扩展一条边,
//因此我们把最小的边找出来,作为最优性剪枝
//不仅如此,因为边越小作为最终解的可能性越大
//实际上在一定程度上优化了程序
}
for (int i = 1; i <= n; i ++) {
tot = 0;
cnt = 1; //赋初值
vis[1] = i; //第一个就选i
tmp -= c[i][tar[i][1]]; //i的最优性剪枝的影响要去掉
//因为剪枝的时候是以还未访问和还未将被访问的点为基础的
//不去掉剪枝就是错误的
lev[i] = 1; //赋值
dfs(1, 1); //只有一个点,也肯定是从1枚举
lev[i] = 0; //回溯
tmp += c[i][tar[i][1]];
}
printf("%d", ans);
return 0;
}
详细
小提示:点击横条可展开更详细的信息
Test #1:
score: 5
Accepted
time: 1ms
memory: 1964kb
input:
1 0
output:
0
result:
ok "0"
Test #2:
score: 5
Accepted
time: 0ms
memory: 2012kb
input:
5 4 1 2 3 1 3 3 1 4 3 1 5 3
output:
12
result:
ok "12"
Test #3:
score: 5
Accepted
time: 0ms
memory: 1792kb
input:
8 7 1 2 3 2 3 3 3 4 3 4 5 3 5 6 3 6 7 3 7 8 3
output:
48
result:
ok "48"
Test #4:
score: 5
Accepted
time: 1ms
memory: 1752kb
input:
8 7 1 2 3 2 3 3 3 4 3 4 5 3 4 6 3 4 7 3 4 8 3
output:
30
result:
ok "30"
Test #5:
score: 5
Accepted
time: 1ms
memory: 1744kb
input:
8 20 6 8 4575 2 3 4575 5 6 4575 4 8 4575 8 1 4575 4 1 4575 3 6 4575 4 5 4575 4 5 4575 2 1 4575 7 8 4...
output:
45750
result:
ok "45750"
Test #6:
score: 5
Accepted
time: 0ms
memory: 1744kb
input:
7 79 2 1 1715 5 7 1715 4 6 1715 3 5 1715 3 4 1715 6 1 1715 1 2 1715 3 7 1715 2 1 1715 5 6 1715 4 7 1...
output:
10290
result:
ok "10290"
Test #7:
score: 5
Accepted
time: 1ms
memory: 1756kb
input:
6 26 1 5 93 4 5 93 1 2 93 6 3 93 4 6 93 1 2 93 6 1 93 6 2 93 1 4 93 3 4 93 4 3 93 6 2 93 1 4 93 5 2 ...
output:
465
result:
ok "465"
Test #8:
score: 5
Accepted
time: 1ms
memory: 1756kb
input:
7 47 5 1 808 4 3 808 5 2 808 2 7 808 2 4 808 3 1 808 5 1 808 4 2 808 5 4 808 5 6 808 3 1 808 1 2 808...
output:
4848
result:
ok "4848"
Test #9:
score: 5
Accepted
time: 2ms
memory: 1800kb
input:
5 806 5 1 4 3 5 2304 2 3 3533 5 2 4 5 1 1712 2 3 3760 4 1 144 5 2 2090 4 5 1603 1 4 862 5 3 2449 2 1...
output:
49
result:
ok "49"
Test #10:
score: 5
Accepted
time: 0ms
memory: 2012kb
input:
6 352 6 5 71 5 1 1591 2 4 106 6 2 3202 6 3 4021 2 4 132 4 2 1164 4 3 1102 2 1 2138 3 2 1755 1 3 1679...
output:
391
result:
ok "391"
Test #11:
score: 5
Accepted
time: 1ms
memory: 1864kb
input:
7 192 6 7 2992 4 1 2830 7 4 1972 2 3 4811 7 4 4400 4 3 1987 4 2 1205 5 1 1590 5 7 4824 2 6 1482 7 5 ...
output:
1037
result:
ok "1037"
Test #12:
score: 5
Accepted
time: 1ms
memory: 1804kb
input:
7 231 1 7 3862 1 6 1559 7 1 3538 2 6 2963 4 7 1170 3 7 1713 7 3 1737 6 7 409 2 5 2522 6 3 2412 2 3 2...
output:
1556
result:
ok "1556"
Test #13:
score: 5
Accepted
time: 1ms
memory: 1820kb
input:
8 196 2 7 3691 8 2 4425 5 8 4748 2 6 339 2 4 1368 1 5 55 6 3 3982 2 5 180 8 1 4436 4 8 4275 6 7 4204...
output:
649
result:
ok "649"
Test #14:
score: 5
Accepted
time: 2ms
memory: 1756kb
input:
8 324 5 7 4787 7 4 1110 3 4 4503 3 4 2527 2 7 1199 7 3 3660 5 1 982 7 2 1675 8 7 160 8 4 3790 7 5 35...
output:
630
result:
ok "630"
Test #15:
score: 5
Accepted
time: 2ms
memory: 1884kb
input:
11 793 1 6 267445 6 9 114589 11 7 356613 2 3 386762 1 3 262296 8 4 232142 7 3 60784 8 11 7827 7 5 16...
output:
78134
result:
ok "78134"
Test #16:
score: 5
Accepted
time: 3ms
memory: 1876kb
input:
11 988 8 1 298264 10 9 94456 9 1 348864 10 1 284796 11 6 203091 10 11 243084 7 1 34101 10 4 417170 4...
output:
58058
result:
ok "58058"
Test #17:
score: 5
Accepted
time: 1ms
memory: 1860kb
input:
12 110 10 8 349233 9 7 431229 3 2 23180 6 7 253401 10 7 376865 8 2 446361 4 9 474356 12 1 314737 6 1...
output:
690550
result:
ok "690550"
Test #18:
score: 5
Accepted
time: 0ms
memory: 1952kb
input:
12 294 2 3 343727 4 7 284269 10 4 146240 3 9 313885 5 6 366277 9 1 28701 7 8 329502 7 12 25620 6 1 5...
output:
190967
result:
ok "190967"
Test #19:
score: 5
Accepted
time: 2ms
memory: 1756kb
input:
12 769 11 1 269107 1 3 238993 6 11 218601 1 4 350327 8 12 23460 6 8 9637 3 7 292001 11 10 123618 6 9...
output:
76380
result:
ok "76380"
Test #20:
score: 5
Accepted
time: 4ms
memory: 1752kb
input:
12 763 11 5 332075 4 3 110459 5 11 412044 9 3 210419 11 1 53214 8 10 457467 6 3 47566 7 12 300566 9 ...
output:
123663
result:
ok "123663"