[编程题]毕业旅行问题

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32M,其他语言64M

小明目前在做一份毕业旅行的规划。打算从北京出发,分别去若干个城市,然后再回到北京,每个城市之间均乘坐高铁,且每个城市只去一次。由于经费有限,希望能够通过合理的路线安排尽可能的省一些路上的花销。给定一组城市和每对城市之间的火车票的价钱,找到每个城市只访问一次并返回起点的最小车费花销。

输入描述:
城市个数n(1<n≤20,包括北京)

城市间的车票价钱 n行n列的矩阵 m[n][n]

输出描述:
最小车费花销 s

输入例子1:
4
0 2 6 5
2 0 4 4
6 4 0 2
5 4 2 0

输出例子1:
13

例子说明1:
共 4 个城市,城市 1 和城市 1 的车费为0,城市 1 和城市 2 之间的车费为 2,城市 1 和城市 3 之间的车费为 6,城市 1 和城市 4 之间的车费为 5,依次类推。假设任意两个城市之间均有单程票可购买,且票价在1000元以内,无需考虑极端情况。

AC代码:状态压缩dp

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
const int  maxn = 1e4+2;
const long long mod = 99997867;
typedef long long ll;

int main(){
    int n;
    int dis[22][22];
    scanf("%d",&n);
    int jh = pow(2,n-1)-1;//二进制表示1111...1110
    vector<vector<int> > dp;
    for(int i=0;i<n;i++){
        dp.push_back(vector<int>());//添加空集合
        for(int j=0;j<=jh;j++){
            dp[i].push_back(99999);//在新增的集合中添加元素
        }
    }
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            scanf("%d",&dis[i][j]);

    for(int i=1;i<n;i++){//设起点为0, dis[i][0]为城市i到0的距离
        dp[i][0] = dis[i][0];
    }
    for(int i=1;i<=jh;i++){//访问城市集合i
        for(int j=0;j<n;j++){//出发点j
            if(j!=0 && i>>(j-1) & 1 == 1)//j不能在待访问城市集合i中,只有j=0时j可以在集合i中,因为需要返回起点0
                continue;
            else{
                for(int k = 1;k<n;k++){//访问城市集合i中的城市k
                    if(i>>(k-1) & 1 == 0)//城市k不在集合i中则跳过
                        continue;
                    else{//城市k在访问城市集合i中,如果j到k再到集合{i-k}的距离小于j到集合i的距离,则更新dp值
                        if(dp[j][i]>(dp[k][i ^ (1<<(k-1))] + dis[j][k]))
                            dp[j][i] = dp[k][i ^ (1<<(k-1))] + dis[j][k];
                    }
                }
            }
        }

    }
    printf("%d",dp[0][jh]);//从0出发访问所有城市(包括起点城市0)一次的最小距离
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值