数据结构与算法-双调旅行售货员问题

  • 题面:氏旅行售货员问题是对给定的平面上n 个点确定一条连接这n 个点的长度最短的哈密顿回路。由于欧氏距离满足三角不等式,所以欧氏旅行售货员问题是一个特殊的具有三角不等式性质的旅行售货员问题。它仍是一个NP 完全问题。最短双调TSP 回路是欧氏旅行售货员问题的特殊情况。平面上n 个点的双调TSP 回路是从最左点开始,严格地由左至右直到最右点,然后严格地由右至左直至最左点,且连接每一个点恰好一次的一条闭合回路。

  • 数据输入:由文件input.txt 给出输入数据。第1 行有1 个正整数n,表示给定的平面上的点数。接下来的n 行中,每行2 个实数,分别表示点的x 坐标和y 坐标。

  • 数据输出: 将计算的最短双调TSP 回路的长度(保留2 位小数)输出到文件output.txt 。

  • 样例输入:
    7

    0 6

    1 0

    2 3

    5 4

    6 1

    7 5

    8 2

  • 样例输出:
    25.58

  • 代码

    /**
    * 请不要质疑1+1=2
     */
    #include <iostream>
    #include <iomanip>
    #include <algorithm>  //sort
    #include <map>
    #include <queue>
    #include <deque>  //双端队列,头可插,尾可插
    #include <string>
    #include <cstring>
    #include <stack>
    #include <cmath>
    #include <fstream>
    #include <ctime>
    #include <climits> //数值的限制范围
    //(double)clock() / CLOCKS_PER_SEC <= 0.95 限制0.95s跑完
    using namespace std;
    
    class Solver {
        //通用属性
    public:
        string name;
        bool isDebug;
    
        Solver(const string name, const bool isDebug) {
            this->name = name;
            this->isDebug = isDebug;
        }
    
        //通用方法
    protected:
        static int QuickRead() {
            int num = 0, flag = 1;
            char ch = getchar();
            //读符号
            while (ch < '0' || ch > '9') {
                if (ch == '-') {
                    flag = -1;
                }
                ch = getchar();
            }
            //读数值
            while (ch >= '0' && ch <= '9') {
                num = (num << 1) + (num << 3) + (ch ^ 48);
                ch = getchar();
            }
            return flag * num;
        }
    
    public:
        void SaveCpp() const {
    
            fstream input;
            fstream output;
    
            input.open("moota.cpp", ios::in);
            const string file = name + ".cpp";
            output.open(file.c_str(), ios::out);
    
            char c = 'O';
            while (!input.eof()) {
                input.get(c);
                output << c;
            }
    
            input.close();
            output.close();
    
        }
    
        void Debug(const string message) const {
            if (isDebug) { cout << message; }
        }
    
    protected:
        //待实现方法
        virtual void BeginPlay() {
            Debug("\n---BeginPlay---\n");
        };
    
        virtual void Playing() {
            Debug("\n---Playing---\n");
        };
    
        virtual void EndPlay() {
            Debug("\n---EndPlay---\n");
        };
    public:
        //外观模式
        void Play() {
            BeginPlay();
            Playing();
            EndPlay();
        }
    };
    
    class Player {
    private:
        string name;
    public:
        Player(const string name) {
            this->name = name;
        }
    
        void Play(Solver* solver) const {
            if (solver->isDebug) {
                cout << "\n" << name << "开始做题\n";
                solver->SaveCpp();
            }
            solver->Play();
        }
    };
    
    class SpecialSolver : public Solver {
    public:
        static const int MAX = int(1e7);
        static const long long INF = (long long)1e18;
    
        SpecialSolver(const string name, const bool isDebug): Solver(name, isDebug) {
        }
    
    private: //实例属性
        int n;
    
        struct Node {
            int x, y;
    
            bool operator<(const Node& other) const {
                return x < other.x;
            }
        } node[1000];
    
        double dp[100][100];
        double dis[100][100];
    private: //实例方法
        void Dp() {
            //dis数组初始化
            for (int i = 1; i <= n; ++i) {
                for (int j = i; j <= n; ++j) {
                    const int gapX = node[i].x - node[j].x;
                    const int gapY = node[i].y - node[j].y;
                    dis[i][j] = sqrt(gapX * gapX + gapY * gapY);
                }
            }
            dp[1][2] = dis[1][2];
            for (int j = 3; j <= n; ++j) {
                for (int i = 1; i < (j - 1); ++i) {
                    dp[i][j] = dp[i][j - 1] + dis[j - 1][j];
                }
                double minValue = MAX;
                for (int k = 1; k < (j - 1); ++k) {
                    minValue = min(minValue, dp[k][j - 1] + dis[k][j]);
                }
                dp[j - 1][j] = minValue;
            }
            dp[n][n] = dp[n - 1][n] + dis[n - 1][n];
        }
    
    protected:
        virtual void BeginPlay() override {
            Solver::BeginPlay();
            cin >> n;
            for (int i = 1; i <= n; ++i) {
                cin >> node[i].x >> node[i].y;
            }
            sort(node + 1, node + n + 1);
        };
    
        virtual void Playing() override {
            Solver::Playing();
            Dp();
        };
    
        virtual void EndPlay() override {
            Solver::EndPlay();
            cout << fixed << setprecision(2) << dp[n][n];
        };
    };
    
    //注意改名字和状态
    Player player("moota");
    SpecialSolver specialSolver("双调旅行售货员问题", true);
    
    int main() {
        player.Play(&specialSolver);
    }
    
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值