SalespersonProblem

思路

设dp(i,j)表示对图的遍历情况为i的二进制数时走到点j的最短路。考虑什么状态可以更新dp(i,j)。 由于每个点只能被经过一次,设更新i的状态为k,那么显然i的第j位为1,k的第j位为0,并且除此之外k和i没有别的不同。所以我们不需要枚举k,只需i^(1<<j)即可。如果k能够更新i,那么肯定是从k的情况时经过的点走过来,也就是k中有1的位置。那么: dp(i,j)=Min{dp(iXOR(1<<j),k)}

其中k和i满足上述的所有条件。

#include<stdio.h>
#include <string.h>
#define MAX 0x7fffffff
int min,n,map[42][42],dis[42];
bool used[42];
void search(int a,int b,int c)
 {
    if (b==n){
        if (map[a][1]+c<min)min=map[a][1]+c;
        return;
    }

    if(c+dis[a]>min)
      return;
    for (int i=1;i<=n;i++)
        if (!used[i]&&i!=a)
            {
                 used[i]=true;
                 search(i,b+1,c+map[a][i]);            
                 used[i]=false;
             }    
 }

void dijk()
 {
     int sel;
     for (int i=1;i<=n;i++) 
         dis[i]=MAX;  
    dis[1]=0;

    for (int i=1;i<=n;i++){
         min=MAX;
         for (int j=1;j<=n;j++)
             if (!used[j]&&dis[j]<min) {
                 min=dis[j];
                 sel=j;
             }
        used[sel]=true;
    for (int j=1;j<=n;j++)
         if (j!=sel)
             if (dis[sel]+map[sel][j]<dis[j])
                 dis[j]=dis[sel]+map[sel][j];        
   }
  memset(used,0,sizeof(used));
 }

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            scanf("%d",&map[i][j]);
    dijk();
    min=MAX;
    used[1]=true;
    search(1,1,0);
    printf("%d\n",min);
    fclose(stdout);
    return 0;    
}

results matching ""

    No results matching ""