covs 2800 送外卖

2800 送外卖

 时间限制: 2 s
 空间限制: 256000 KB
 题目等级 : 钻石 Diamond
题目描述 Description

有一个送外卖的,他手上有n份订单,他要把n份东西,分别送达n个不同的客户的手上。n个不同的客户分别在1~n个编号的城市中。送外卖的从0号城市出发,然后n个城市都要走一次(一个城市可以走多次),最后还要回到0点(他的单位),请问最短时间是多少。现在已知任意两个城市的直接通路的时间。

输入描述 Input Description

第一行一个正整数n (1<=n<=15)

接下来是一个(n+1)*(n+1)的矩阵,矩阵中的数均为不超过10000的正整数。矩阵的i行j列表示第i-1号城市和j-1号城市之间直接通路的时间。当然城市a到城市b的直接通路时间和城市b到城市a的直接通路时间不一定相同,也就是说道路都是单向的。

输出描述 Output Description

一个正整数表示最少花费的时间

样例输入 Sample Input
3
0 1 10 10
1 0 1 2
10 1 0 10
10 2 10 0
样例输出 Sample Output

8

数据范围及提示 Data Size & Hint

1<=n<=15

/*
S表示已经走过的城市,1表示已经走过,0表示未走过(位标记集合)
首先对于原图进行floyd,得到一个最短路的图(16^3,绰绰有余啊)
然后遍历所有的集合
f[x][S]中,x表示完成S集合时,最后走到的是x,然后储存的值就是到这样的状态需要的最小花费。
可能觉得奇怪,假如一开始进行floyd,那么a->b就变成a->c->b,那么在a已入的情况下加入b,那c不是可以直接加入的吗?
不要慌,a->c->b,就是a—>c,c->b,这两条不会被改变(就算被改变,继续递归下去想吧),就不会丢掉c了。
方程:f[x][S]=min(f[x][S],f[k][S^(1<<(x-1))]+_map[k][x]){其中,k已经在S中}
最后不要忘了加_map[x][0],要回去的233
*/
#include <iostream>
#include <cstdio>
using namespace std;
int n;
int f[16][66000],_map[16][16];
int main()
{
   cin>>n;
   for(int i=0;i<=n;i++){
    for(int j=0;j<=n;j++){
        scanf("%d",&_map[i][j]);
    }
   }
   //floyd
   for(int k=0;k<=n;k++){
     for(int i=0;i<=n;i++){
        for(int j=0;j<=n;j++){
            if(i!=j&&i!=k&&j!=k){
                if(_map[i][k]+_map[k][j]<_map[i][j])
                    _map[i][j]=_map[i][k]+_map[k][j];
            }
        }
     }
   }
   int Smax=(1<<n)-1;
   for(int S=1;S<=Smax;S++){
     for(int i=1;i<=n;i++){
        if(S&(1<<(i-1))){
            if( (S^(1<<(i-1))) ==0){
                f[i][S]=_map[0][i];
            }else{
                f[i][S]=99999999;
                for(int j=1;j<=n;j++){
                    if(S&(1<<(j-1)) && i!=j){
                        f[i][S]=min(f[i][S],f[j][S^(1<<(i-1))]+_map[j][i]);
                    }
                }
            }

        }
     }
   }

   int ans=99999999;
   for(int i=1;i<=n;i++){
    ans=min(ans,f[i][Smax]+_map[i][0]);
   }
   cout<<ans;
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章