P1433 吃奶酪

点击查看代码
#include <bits/stdc++.h>
using namespace std;

int n;
double x[20], y[20];//记录多组坐标
double w[20][20]; // 【优化1】预处理距离矩阵
double ans = 1e9;
bool vis[20];//检查是否访问过

// 计算两点距离
double dist_func(int i, int j) {
    return sqrt((x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]));
}
//1.状态定义,当前点,当前经过点的数量,走的总距离
void dfs(int now, int count, double sum_dist) {
    // 2.剪枝,最优性剪枝(底线是贪心)
    if (sum_dist >= ans) return;
    //3.截止条件,访问过n个点
    if (count == n) {
        ans = min(ans, sum_dist);
        return;
    }
    //4.枚举选择,访问没走过的点
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            vis[i] = true;
            // 直接查表 w[now][i],不用重复算 sqrt
            dfs(i, count + 1, sum_dist + w[now][i]);
            //5.回溯
            vis[i] = false;
        }
    }
}

int main() {
    //读入数据,每一组坐标存在一个索引指向的x,y数组中
    cin >> n;
    x[0] = 0; y[0] = 0;
    for (int i = 1; i <= n; i++) cin >> x[i] >> y[i];

    // 优化1预处理两两点之间的距离,这样在dfs时就不用调用sqrt函数了,而是直接查表就可以了,避免了很多重复计算
    for(int i=0; i<=n; i++){
        for(int j=0; j<=n; j++){
            w[i][j] = dist_func(i, j);
        }
    }

    //优化2,贪心搜索,先找到一个看上去不错的解
    double greedy_sum = 0;
    int cur = 0;
    bool g_vis[20] = {0};
    
    for(int step=1; step<=n; step++){
        int next_best = -1;
        double min_d = 1e9;
        
        // 每次找离当前点最近的未访问点
        for(int i=1; i<=n; i++){
            if(!g_vis[i] && w[cur][i] < min_d){
                min_d = w[cur][i];
                next_best = i;
            }
        }
        g_vis[next_best] = 1;
        greedy_sum += min_d;
        cur = next_best;
    }
    //把贪心结果作为最优性剪枝的底线,这样可以避免初期很多无效的搜索
    ans = greedy_sum; 

    // 开始真正的搜索
    dfs(0, 0, 0.0);

    printf("%.2f\n", ans);
    return 0;
}
posted @ 2026-01-06 16:41  gosaky  阅读(3)  评论(0)    收藏  举报