AtCoder題解 —— AtCoder Beginner Contest 183 —— C - Travel

努力的老周發表於2020-11-16

題目相關

題目連結

AtCoder Beginner Contest 183 C 題,https://atcoder.jp/contests/abc183/tasks/abc183_c

Problem Statement

There are N cities. The time it takes to travel from City i to City j is Ti,j.

Among those paths that start at City 1, visit all other cities exactly once, and then go back to City 1, how many paths take the total time of exactly K to travel along?

Input

Input is given from Standard Input in the following format:

N K
T1,1 ... T1,N
.
.
TN,1 ... TN,N

Output

Print the answer as an integer.

Samples1

Sample Input 1

4 330
0 1 10 100
1 0 20 200
10 20 0 300
100 200 300 0

Sample Output 1

2

Explaination

There are six paths that start at City 1, visit all other cities exactly once, and then go back to City 1:

  • 1→2→3→4→1
  • 1→2→4→3→1
  • 1→3→2→4→1
  • 1→3→4→2→1
  • 1→4→2→3→1
  • 1→4→3→2→1

The times it takes to travel along these paths are 421, 511, 330, 511, 330, and 421, respectively, among which two are exactly 330.

Samples2

Sample Input 2

5 5
0 1 1 1 1
1 0 1 1 1
1 1 0 1 1
1 1 1 0 1
1 1 1 1 0

Sample Output 2

24

Explaination

In whatever order we visit the cities, it will take the total time of 5 to travel.

Constraints

  • 2≤N≤8
  • If i≠j, 1≤Ti,j≤10^8.
  • Ti,i=0
  • Ti,j=Tj,i
  • 1≤K≤10^9
  • All values in input are integers.

題解報告

題目翻譯

有 N 個城市,從城市 i 到城市 j 需要的時間記為 Ti,j。問從城市 1 出發,經過所有的其他城市,再回到城市 1,而且每個城市只能走一次。求需要時間正好為 K 的線路個數。

樣例資料分析

這個題目樣例i資料解釋中已經說明的非常詳細,我們不需要分析樣例資料。

題目分析

根據樣例資料 1,一共有 4 個城市,我們知道從城市 1 出發遍歷所有城市,這就是一個全排列問題。使用模擬演算法,基本思路就是,寫出所有從 1 出發的全排列,然後計算出這個路線需要的時間,如果和 K 相同,我們就找到了一個答案。

考慮到本題的資料 N 最大為 8。因此 8 個城市,從 1 出發的全排列為 7!=5040,也就是說模擬演算法是可以在規定的時間內完成的。這樣本問題就轉換為如何寫出全排列。

使用 C++ STL 寫出全排列是一個非常容易的事情。我們可以使用 algrothim 庫中的 next_permutation() 函式即可完成這個任務。

AC 參考程式碼

//https://atcoder.jp/contests/abc183/tasks/abc183_c
//C - Travel
#include <bits/stdc++.h>

using namespace std;

const int MAXN=10;
int nums[MAXN][MAXN];

int main() {
    int n,k;
    cin>>n>>k;

    int i;
    for (i=1; i<=n; i++) {
        for (int j=1; j<=n; j++) {
            cin>>nums[i][j];
        }
    }

    vector<int> idx(n+2);
    iota(idx.begin(), idx.end(), 0);
    idx[n+1]=1;
    int ans=0;
    do {
        int sum=0;
        for (i=2; i<=n+1; i++) {
            sum+=nums[idx[i-1]][idx[i]];
        }
        if (sum==k) {
            ans++;
        }
    } while (next_permutation(idx.begin()+2, idx.end()-1));

    cout<<ans<<"\n";

    return 0;
}

時間複雜度

O(N^2)。主要的時間消耗在讀取資料上。

空間複雜度

O(N^2)。

問題擴充套件

當 N 持續擴大。比如 N 變成 11,這樣 10!=3.7e6,繼續使用模擬演算法,就不一定能通過了。該如何改進演算法?我去,我一下也沒想明白。鴿一下。

相關文章