TIOJ-1554

給一個$N\times N$的矩陣,取$N$個數字滿足他們都在不同行不同列,求最大的數字乘積。

$N\le 20, a_{ij}\ge 0$


我有點把題目過度簡化,不過方向就是這樣,剩下的只差在實作細節。

$\mathcal{O}(N^22^N)$ solution

注意N很小,所以可以直接枚舉目前要拿第幾行,且每個數字是否被拿(位元DP)。
然後每一行再枚舉要拿哪一列,這樣會是$\mathcal{O}(N^22^N)$。

附上TLE的code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
-------------- | /
| | /
| | /
| * |/ | | ------ *
| | | | / \
| | |\ | | | |\ |
\ | | | \ | | | | \ |
\ | | | \ | | \ / \ |
V | | \ \__/| ----- \ |
*/
#include <bits/stdc++.h>
using namespace std;

#define EmiliaMyWife ios::sync_with_stdio(0); cin.tie(NULL);
#define mem(i,j) memset(i,j,sizeof (i));
using ll = int64_t;
using ull = uint64_t;
using ld = long double;
using uint = uint32_t;
const double EPS = 1e-8;
const int INF = 0x3F3F3F3F;
const ll LINF = 4611686018427387903;
const int MOD = 1e9+7;
/*-----------------------------------------------------------------------------------------------------*/

signed main() {
EmiliaMyWife

int n;
cin >> n;
vector<double> dp(1 << n);
vector<vector<int>> arr(n, vector<int>(n));
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
cin >> arr[i][j];
dp[0] = 1;
for(int i = 0; i < n; i++)
for(int j = (1 << n) - 1; j; j--)
for(int k = 0; k < n; k++)
if((j >> k) & 1)
dp[j] = max(dp[j], dp[j ^ (1 << k)] * arr[i][k] / 100);
cout << fixed << setprecision(2) << dp[(1 << n) - 1] * 100 << '\n';


return 0;
}

$\mathcal{O}(N2^N)$ solution

注意到在枚舉到第$i$列時,我們只需要知道已經取$i$個數字的狀態(也就是位元表示中,1的數量剛好$i$個),所以可以用__builtin_pop_count()預處理。

這樣整個枚舉過程所有$2^N$的狀態只會被枚舉一次,複雜度$\mathcal{O}((N+2^N)N)=\mathcal{O}(N2^N)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/*
-------------- | /
| | /
| | /
| * |/ | | ------ *
| | | | / \
| | |\ | | | |\ |
\ | | | \ | | | | \ |
\ | | | \ | | \ / \ |
V | | \ \__/| ----- \ |
*/
#include <bits/stdc++.h>
using namespace std;

#define EmiliaMyWife ios::sync_with_stdio(0); cin.tie(NULL);
#define mem(i,j) memset(i,j,sizeof (i));
using ll = int64_t;
using ull = uint64_t;
using ld = long double;
using uint = uint32_t;
const double EPS = 1e-8;
const int INF = 0x3F3F3F3F;
const ll LINF = 4611686018427387903;
const int MOD = 1e9+7;
/*-----------------------------------------------------------------------------------------------------*/

signed main() {
EmiliaMyWife

int n;
cin >> n;
vector<double> dp(1 << n);
vector<vector<int>> arr(n, vector<int>(n)), has(n);
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
cin >> arr[i][j];
for(int i = 1; i < (1 << n); i++)
has[__builtin_popcount(i) - 1].push_back(i);
dp[0] = 1;
for(int i = 0; i < n; i++)
for(int j : has[i])
for(int k = 0; k < n; k++)
if((j >> k) & 1)
dp[j] = max(dp[j], dp[j ^ (1 << k)] * arr[i][k] / 100);
cout << fixed << setprecision(2) << dp[(1 << n) - 1] * 100 << '\n';


return 0;
}