zoukankan      html  css  js  c++  java
  • 07_旅行商问题(TSP问题,货郎担问题,经典NPC难题)

    问题来源:刘汝佳《算法竞赛入门经典--训练指南》 P61 问题9:

    问题描述:有n(n<=15)个城市,两两之间均有道路直接相连,给出每两个城市i和j之间的道路长度L[i][j],求一条经过每个城市一次且仅一次,最后回到起点的路线,使得经过的道路总长度最短(城市编号为0~n-1)。

    分析: 1.因为最后走的路线为一个环,可以设城市0为起点城市。

        2.将每个城市看作二进制的一个位(1代表有,0代表没有),则数k可以表示一些城市的集合(例如k=13,二进制表示为1101,表示城市0,2,3的集合),我们可以求得k<=2^15-1,令  aim=2^15-1;

        3.dp[k][j]表示经过了k集合中的所有城市并且以j城市为终点的路径的最小值

        则dp[k][j] = Min{dp[k][j],dp[k-j][i]+dis[i][j] | (0<=i<=n-1 && i属于集合k)};(其中k-j表示集合k中去掉数j后的集合(所以j应该是集合k中的元素)),

    例题链接:http://acm.fzu.edu.cn/problem.php?pid=2186

    例题: fzu 2186

    Problem 2186 小明的迷宫

    Accept: 88    Submit: 270
    Time Limit: 1000 mSec    Memory Limit : 32768 KB

     Problem Description

    小明误入迷宫,塞翁失马焉知非福,原来在迷宫中还藏着一些财宝,小明想获得所有的财宝并离开迷宫。因为小明还是学生,还有家庭作业要做,所以他想尽快获得所有财宝并离开迷宫。

     Input

    有多组测试数据。

    每组数据第一行给出两个正整数n,m(0<n,m<=100)。代表迷宫的长和宽。

    接着n行,每行m个整数。正数代表财宝(财宝的个数不超过10);负数代表墙,无法通过;0代表通道。

    每次移动到相邻的格子,所花费的时间是1秒。小明只能按上、下、左、右四个方向移动。

    小明的初始位置是(1,1)。迷宫的出口也在(1,1)。

     Output

    输出获得所有财宝并逃出迷宫所花费的最小时间,如果无法完成目标则输出-1。

     Sample Input

    3 3
    0 0 0
    0 100 0
    0 0 0
    2 2
    1 1
    1 1

     Sample Output

    4
    4

     Source

    FOJ有奖月赛-2015年03月
    思路:先将出口和宝藏之间的距离全部通过DFS求出来(出口的地方需要特殊判断和处理),接下来就是裸的TSP问题dp+状压
      1 #include "stdio.h"
      2 #include "string.h"
      3 #include "queue"
      4 using namespace std;
      5 #define N 105
      6 #define INF 0x3fffffff
      7 
      8 int m,n;
      9 int map[N][N],mark[N][N];
     10 int dis[15][15],flag[15],dist[15];
     11 int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
     12 
     13 int dp[5050][15],b[15];
     14 int inline Min(int a,int b){ return a<b?a:b; }
     15 
     16 struct Point
     17 {
     18     int x,y;
     19 } point[15];
     20 
     21 struct node
     22 {
     23     int x,y;
     24     int length;
     25 };
     26 
     27 void DFS(int start,int x,int y,int length)
     28 {
     29     int i,k;
     30     int x1,y1;
     31     queue<node> q;
     32     node cur,next;
     33     cur.x = x;
     34     cur.y = y;
     35     cur.length = 0;
     36     q.push(cur);
     37     while(!q.empty())
     38     {
     39         cur = q.front();
     40         q.pop();
     41         for(i=0; i<4; i++)
     42         {
     43             next.x = x1 = cur.x+dir[i][0];
     44             next.y = y1 = cur.y+dir[i][1];
     45             next.length = cur.length+1;
     46             if(x1<=0 || x1>n || y1<=0 || y1>m || mark[x1][y1]!=0 || map[x1][y1]<0)
     47                 continue;
     48             if(map[x1][y1]>0)
     49             {
     50                 k = map[x1][y1];
     51                 dis[start][k] = dis[k][start] = next.length;
     52             }
     53             mark[x1][y1] = 1;
     54             q.push(next);
     55         }
     56     }
     57 }
     58 
     59 int main()
     60 {
     61     int ans;
     62     int i,j,k,num,l;
     63     b[0] = 1;
     64     for(i=1; i<15; i++)  //b[i]存的2^i
     65         b[i] = b[i-1]*2;
     66     while(scanf("%d %d",&n,&m)!=EOF)
     67     {
     68         num = 2;
     69         for(i=1; i<=n; ++i)
     70         {
     71             for(j=1; j<=m; j++)
     72             {
     73                 scanf("%d",&map[i][j]);
     74                 if(i==1 && j==1&& map[i][j]>0) num--;
     75                 if(map[i][j]>0)      map[i][j]= num++;
     76                 else if(map[i][j]<0) map[i][j]=-1;
     77             }
     78         }
     79         if(map[1][1]<0)
     80         {
     81             printf("-1
    ");
     82             continue;
     83         }
     84         map[1][1] = 1;
     85         for(i=1; i<=n; ++i)
     86         {
     87             for(j=1; j<=m; j++)
     88             {
     89                 if(map[i][j]>0)
     90                 {
     91                     k = map[i][j];
     92                     point[k].x = i, point[k].y = j;
     93                 }
     94 
     95             }
     96         }
     97         for(i=1; i<num; i++)
     98         {
     99             for(j=1; j<num; j++)
    100                 dis[i][j] = INF;
    101             dis[i][i]= 0;
    102         }
    103         for(i=1; i<num; i++)  //以每个点为起点广搜,求出任意两点间的最短距离
    104         {
    105             memset(mark,0,sizeof(mark));
    106             mark[point[i].x][point[i].y] = 1;
    107             DFS(i,point[i].x,point[i].y,0);
    108         }
    109         num--;  //宝藏编号为1~num
    110         int tt = 0;
    111         for(i=2; i<=num; i++)
    112         {
    113             if(dis[1][i]==INF)  //只要存在一个INF,表示至少有一个宝藏不可达,输出-1
    114                 tt = 1;
    115         }
    116         if(tt==1)
    117         {
    118             printf("-1
    ");
    119             continue;
    120         }
    121         int aim =b[num+1]-2;//y因为从2^1开始到2^num,则aim = 2^(num+1)-1-2^0
    122         for(i=0; i<=aim; i++)
    123         {
    124             for(j=0; j<=num; j++)
    125                 dp[i][j] = INF;
    126         }
    127         dp[2][1] = 0; 
    128         for(l=2; l<=aim; l++) //一个集合l
    129         {
    130             for(i=1; i<=num; i++)
    131             {
    132                 for(j=1; j<=num; j++)
    133                 {
    134                     if(i==j) continue;
    135                     if((b[i]&l)==0) continue;  //必须满足i  在集合l中,不满足,跳过,
    136                     if((b[j]&l)==1) continue;  //必须满足j不在集合l中,不满足,跳过,
    137                     if(dp[l][i]==INF) continue;
    138                      dp[l|b[j]][j]=Min(dp[l|b[j]][j],dp[l][i]+dis[i][j]);
    139                 }
    140             }
    141         }
    142         ans = INF;
    143         for(i=2; i<=num; i++)
    144             ans = Min(ans,dp[aim][i]+dis[i][1]);
    145         printf("%d
    ",ans);
    146     }
    147     return 0;
    148 }
  • 相关阅读:
    null in ABAP and nullpointer in Java
    SAP ABAP SM50事务码和Hybris Commerce的线程管理器
    Hybris service layer和SAP CRM WebClient UI架构的横向比较
    SAP ABAP和Linux系统里如何检查网络传输的数据量
    SAP CRM WebClient UI和Hybris的controller是如何被调用的
    SAP CRM和Cloud for Customer订单中的业务伙伴的自动决定机制
    SAP CRM WebClient UI和Hybris CommerceUI tag的渲染逻辑
    SAP BSP和JSP页面里UI元素的ID生成逻辑
    微信jsapi支付
    微信jsapi退款操作
  • 原文地址:https://www.cnblogs.com/ruo-yu/p/4385291.html
Copyright © 2011-2022 走看看