CF2041C Cube
CF2041C Cube
题意
给出一个 \(n\times n\times n \pod{2\le n\le 12}\) 的三维数组 \(a\),你需要选出 \(n\) 个数字 \(a_{x_1,y_1,z_1},a_{x_2,y_2,z_2},\cdots,a_{x_n,y_n,z_n}\),且 \(x_i\neq x_j,y_i\neq y_j,c_i\neq c_j \pod{1\le i,j\le n,i\neq j}\),求 \(\min \sum_{i=1}^n a_{x_i,y_i,z_i}\)。
思路
看到 \(n\le 12\),一眼状压 dp。由题意可以知道 \(x,y,z\) 数组均为一个全排列。令 \(x_i=i\),设 \(f_{i,s1,s2}\) 表示选择 \(i\) 个数后 \(y,z\) 数组的状态(由于 \(y,z\) 数组为全排列,所以状态可以表示成数字 \(i\) 是否存在),则可以很容易得出转移方程 \(f_{i,s1|(1<<j),s2|(1<<k)} = \min \{f_{i-1,s1,s2}+a_{i,j,k}\}\),其中 \(j,k\) 没有出现在状态 \(s1,s2\) 中,最后答案即为 \(f_{n,(1<<n)-1,(1<<n)-1}\)。
容易发现时空复杂度均为 \(O(n^3\times 2^n\times 2^n)\),显然对于 \(n\le 12\) 不能通过。对于空间可以采取滚动数组优化。因为 \(f_{i,s1,s2}\) 表示选择了 \(i\) 个数,那么 \(s1,s2\) 均可以表示选择 \(i-1\) 个数的状态,很容易预处理出来,时间复杂度也可以减小,可以通过本题。
代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int n,a[13][13][13],f[1<<13][1<<13][2];
vector<int> fc[13];
int count(int x){
int res=0;
while(x)
res++,x&=(x-1);
return res;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>n;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
for(int k=0;k<n;k++){
cin>>a[i][j][k];
}
}
}
for(int s=0;s<(1<<n);s++)
fc[count(s)].push_back(s);
for(int i=0;i<n;i++){
for(int s:fc[i])
for(int s2:fc[i])
f[s][s2][0]=f[s][s2][1];
for(int s:fc[i+1])
for(int s2:fc[i+1])
f[s][s2][1]=1e9;
for(int j=0;j<n;j++){
for(int k=0;k<n;k++){
for(int s:fc[i]){
if(s&(1<<j)) continue;
for(int s2:fc[i]){
if(s2&(1<<k)) continue;
f[s|(1<<j)][s2|(1<<k)][1]=min(f[s|(1<<j)][s2|(1<<k)][1],f[s][s2][0]+a[i][j][k]);
}
}
}
}
}
cout<<f[(1<<n)-1][(1<<n)-1][1];
return 0;
}

浙公网安备 33010602011771号