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;
}


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