zoukankan      html  css  js  c++  java
  • 入门OJ:售货员的难题

    题目描述

    某乡有n个村庄(1<n<15),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且A村到B村与B村到A村的路大多不同。为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程最短。请你帮他选择一条最短的路。

    输入格式

    村庄数n和各村之间的路程(均是整数)。

    输出格式

    最短的路程


    走完n个点的最短路可以由走完n-1个点的最短路加上最后走的边的边权更新而来,所以不难想到我们可以用动规来做这题。而一个点只能被经过一次,并且n<15,我们可以用状压。

    设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<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 16
    using namespace std;
     
    int dis[maxn][maxn],dp[1<<maxn][maxn];
    int n;
     
    int main(){
        scanf("%d",&n);
        for(register int i=0;i<n;i++){
            for(register int j=0;j<n;j++) scanf("%d",&dis[i][j]);
        }
        memset(dp,0x3f,sizeof dp),dp[1][0]=0;
        for(register int i=1;i<1<<n;i++){
            for(register int j=0;j<n;j++) if((i>>j)&1){
                for(register int k=0;k<n;k++) if(j!=k&&((i^(1<<j))>>k)&1){
                    dp[i][j]=min(dp[i][j],dp[i^(1<<j)][k]+dis[k][j]);
                }
            }
        }
     
        int mini=0x3f3f3f3f;
        for(register int i=1;i<n;i++) mini=min(mini,dp[(1<<n)-1][i]+dis[i][0]);
        printf("%d
    ",mini);
        return 0;
    }
    

    时间复杂度为O(N^2 * 2^N)

  • 相关阅读:
    浅析8种常用排序
    尾递归和线性递归
    线性表之顺序表
    安装minikube
    error while loading shared libraries: libatomic.so.1: cannot open shared object file: No such file or directory
    fatal error: 'openssl/conf.h' file not found
    GraphQL 最突出的架构优势是什么?
    mac 安装 brew
    Clean Architecture
    sql优化
  • 原文地址:https://www.cnblogs.com/akura/p/10896591.html
Copyright © 2011-2022 走看看