旅行商问题

NPC问题,不存在多项式时间的算法,但是在算法中可以做剪枝优化:

1. 第一次写的算法,缺少剪枝:  当前路径 >= 之前算出的最短路径, 则当前路径不在继续遍历

#include <cstdio>
#include <iostream>
#include <cstring>

using namespace std;

int N;
int map[12][12];
int flag[12];

int solve(int start) {
    int i,val, all_visited = 1, min = 999999999;

    for (i = 2; i <= N; i++) {
        if (flag[i] != 0 || map[start][i] == 0) {
            continue;
        }
        all_visited = 0;
        flag[i] = 1; //visited
        val = map[start][i] + solve(i);
        if (val < min) {
            min = val;
        }
        flag[i] = 0;
    }
    if (all_visited) {
        return map[start][1];
    } else {
        return min;
    }
}

int main(int argc, char** argv)
{
    int tc, T, i, j;
    // freopen("input.txt", "r", stdin);
    cin >> T;
    for(tc = 0; tc < T; tc++)
    {
        cin>>N;
        for (i = 1; i <= N; i++) {
            for (j = 1; j <= N; j++) {
                cin>>map[i][j];
            }
        }

        memset(flag, 0x00, 12*sizeof(int));
        printf("%d\n", solve(1));
    }

    return 0;
}

2. 优化算法,路径判断剪枝

#include <cstdio>
#include <iostream>
#include <cstring>

using namespace std;

int N, cost, min_cost;
int map[13][13];
int flag[13];
int sum;

void solve(int start) {
    int i;

    if (sum >= N) {
        if (map[start][1]!=0 && cost + map[start][1] < min_cost) {
            min_cost = cost + map[start][1];
        }
        return;
    }

    for (i = 2; i <= N; i++) {
        if (flag[i] != 0 || map[start][i] == 0 || cost + map[start][i] >= min_cost) {
            continue;
        }
        flag[i] = 1; //visited
        cost += map[start][i];
        sum++;
        solve(i);
        sum--;
        flag[i] = 0;
        cost -= map[start][i];
    }
}

int main(int argc, char** argv)
{
    int tc, T, i, j;
    //freopen("input.txt", "r", stdin);
    cin >> T;
    for(tc = 0; tc < T; tc++)
    {
        cin>>N;
        for (i = 1; i <= N; i++) {
            for (j = 1; j <= N; j++) {
                    cin>>map[i][j];
            }
        }

        memset(flag, 0x00, 13*sizeof(int));
        cost = 0; min_cost = 99999999999;
        sum = 1;
        solve(1);
        cout<<min_cost<<endl;
    }

    return 0;
}

注意红色代码,不要遗漏

时间: 2024-10-02 22:57:10

旅行商问题的相关文章

UVA - 1347 Tour 双调欧几里得旅行商问题

题目大意:给出n个点,要求你从最左边那个点走到最右边那个点,每个点都要被遍历过,且每个点只能走一次,问形成的最短距离是多少 解题思路:用dp[i][j]表示第一个人走到了第i个点,第二个人走到了第j个点且已经遍历了1–max(i,j)的所有点的最短距离.因为dp[i][j] = dp[j][i]的,所以我们设i > j的 那么就有 当j < i-1 时,dp[i][j] = dp[i-1][j] + dis(i, i -1) 当j == i + 1时情况就比较特别了,这里将j用i-1代替 dp

【算法学习】双调欧几里得旅行商问题(动态规划)(转)

双调欧几里得旅行商问题是一个经典动态规划问题.<算法导论(第二版)>思考题15-1和北京大学OJ2677都出现了这个题目. 旅行商问题描述:平面上n个点,确定一条连接各点的最短闭合旅程.这个解的一般形式为NP的(在多项式时间内可以求出) J.L. Bentley 建议通过只考虑双调旅程(bitonictour)来简化问题,这种旅程即为从最左点开始,严格地从左到右直至最右点,然后严格地从右到左直至出发点.下图(b)显示了 同样的7个点的最短双调路线.在这种情况下,多项式的算法是可能的.事实上,存

HDU 4824 双调旅行商问题

由于跳转一次需要400,大于在扇道内转一圈,所以应尽可能少的跳转扇道,就转换成了双调旅行商问题, 即从0区开始访问到最大的区域,再返回0区,所有中间点需走到一次 #include "stdio.h" #include "string.h" #include "math.h" #include "algorithm" using namespace std; struct node { int x,y; }a[1010]; in

hdu3001 Travelling 旅行商问题 状态压缩DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 Travelling Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4642    Accepted Submission(s): 1531 Problem Description After coding so many days,

2014年百度之星程序设计大赛 - 资格赛 1002 Disk Schedule(双调欧几里得旅行商问题)

Problem Description 有很多从磁盘读取数据的需求,包括顺序读取.随机读取.为了提高效率,需要人为安排磁盘读取.然而,在现实中,这种做法很复杂.我们考虑一个相对简单的场景.磁盘有许多轨道,每个轨道有许多扇区,用于存储数据.当我们想在特定扇区来读取数据时,磁头需要跳转到特定的轨道.具体扇区进行读取操作.为了简单,我们假设磁头可以在某个轨道顺时针或逆时针匀速旋转,旋转一周的时间是360个单位时间.磁头也可以随意移动到某个轨道进行读取,每跳转到一个相邻轨道的时间为400个单位时间,跳转

POJ2677 Tour(DP+双调欧几里得旅行商问题)

Tour Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3929   Accepted: 1761 Description John Doe, a skilled pilot, enjoys traveling. While on vacation, he rents a small plane and starts visiting beautiful places. To save money, John must

模拟退火算法求解旅行商问题(附c和matlab源代码)

前几天在做孔群加工问题,各种假设到最后就是求解旅行商问题了,因为原本就有matlab代码模板所以当时就改了城市坐标直接用了,发现运行速度惨不忍睹,最后用上了两个队友的电脑一起跑.这次模拟结束后在想用c语言来实现的话应该可以提高不少效率.关于模拟退火和旅行商问题的介绍我就不赘述了,网上各路大神说的都很详细,我下面就把c语言和matlab代码先附上. c语言: 1 #ifndef _OPTION_H 2 #define _OPTION_H 3 /* 4 * T0 表示 初始温度 5 * Tf 表示

poj3311 Hie with the Pie 旅行商问题(TSP)

题目链接 http://poj.org/problem?id=3311 Hie with the Pie Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5094   Accepted: 2716 Description The Pizazz Pizzeria prides itself in delivering pizzas to its customers as fast as possible. Unfortuna

《算法导论》思考题15-1 双调欧几里得旅行商问题(动态规划)

欧几里得旅行商问题 是对平面上给定的n个点确定一条连接各点的最短闭合旅程的问题.图a给出了7个点问题的解,这个问题的一般形式是NP完全的,故其解需要多于多项式的时间. J.K.Bentley建议通过只考虑双调旅程来简化问题,这种旅程即为从最左点开始,严格从左到最右点,再严格地从最右点回到最左点.图b显示了同样的7个点的问题的最短双调路线,在这种情况下,多项式的时间的算法是有可能的. 描述一个确定最优双调路线的O(n^2)时间的算法.可以假设任何两点的x坐标都不相同. 解法: 读了很多遍这个题,也

hdu 4824 Disk Schedule(双调欧几里得旅行商问题)

题目链接:hdu 4824 Disk Schedule 题目大意:中文题. 解题思路:需要的时,很明显每到一层是要读取一次数据的,但是因为需要返回00,所以有些层的数据可以在返回的过程中读取会较优.于是转化成了双调欧几里得旅行商问题. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int N = 1