思路:深度搜索复杂度N!过不了。考虑动态规划:将已经选择的列记为1,未选择表示0,二进制压缩,例如110,就表示选择了第1列和第2列。
d(i, t)表示当前已经匹配了i行,选择了t这些列。状态转移:
for(int i = 0; i < n; ++i) { int x = 1 << i; if(x & val) d = max(d, like[row][i] + dfs(row+1, val - x, k-1)); }
此时总的状态数就是1<<n,相比N!是极大的优化,减少了很多重复情况的搜索。
用记忆化搜索,代码很好写。
#include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #include <utility> #include <string> #include <iostream> #include <map> #include <set> #include <vector> #include <queue> #include <stack> using namespace std; #pragma comment(linker, "/STACK:1024000000,1024000000") #define eps 1e-10 #define inf 0x3f3f3f3f #define PI pair<int, int> typedef long long LL; const int maxn = 13 + 5; int like[maxn][maxn], dp[maxn][1<<13]; int n, ans; int dfs(int row, int val, int k) { //row表示行,k表示当前选择了多少列 if(dp[row][val] != -1) return dp[row][val]; int &d = dp[row][val]; if(k == 1) { //边界 for(int i = 0; i < n; ++i) { int x = 1 << i; if(x & val) return d = like[row][i]; } } for(int i = 0; i < n; ++i) { int x = 1 << i; if(x & val) d = max(d, like[row][i] + dfs(row+1, val - x, k-1)); } return d; } int main() { while(scanf("%d", &n) == 1) { for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) { scanf("%d", &like[i][j]); } memset(dp, -1, sizeof(dp)); int start = (1<<n)-1; printf("%d\n", dfs(0, start, n)); } return 0; }
如有不当之处欢迎指出!