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)

  • 相关阅读:
    Java-MyBatis:MyBatis 3 入门
    Java-MyBatis-3.0:MyBatis 3 简介
    DB-MySQL:MySQL 教程
    DB-MySQL:MySQL GROUP BY
    DB-MySQL:MySQL 连接的使用
    人行
    PHP 面试题数组篇[ 整理中 ]
    java中Condition类的详细介绍(详解)
    java中Condition类的详细介绍(详解)
    java中Condition类的详细介绍(详解)
  • 原文地址:https://www.cnblogs.com/akura/p/10896591.html
Copyright © 2011-2022 走看看