考察:记忆化搜索
思路:
dfs模拟即可,用map判断当前数字出现过几次.但是回溯的时候要注意,如果本该有的数字没有说明被凑成了一对,但是恢复要恢复成1,如果有就要去掉这个数字.
本蒟蒻真的写得很繁琐,这位大佬利用位运算0 1的性质避免了判断2,很妙 GO
网上题解基本都用了步数作为参数,本蒟蒻是完全没想到.
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <vector> 6 #include <map> 7 using namespace std; 8 const int N = 42; 9 bool st[N][N][N][N]; 10 vector<int> v[5]; 11 map<int,int> mp; 12 int n,ans,cnt; 13 void dfs(int i,int j,int k,int w) 14 { 15 if(i>=n&&j>=n&&k>=n&&w>=n) return; 16 if(st[i][j][k][w]) return; 17 st[i][j][k][w] = 1; 18 if(i<n) 19 { 20 if(mp.size()>=5) return; 21 mp[v[1][i]]++; 22 if(mp[v[1][i]]>=2) 23 cnt++,mp.erase(v[1][i]); 24 ans = max(cnt,ans); 25 dfs(i+1,j,k,w); 26 if(!mp.count(v[1][i])) cnt--,mp[v[1][i]] = 1; 27 else mp.erase(v[1][i]); 28 } 29 if(j<n) 30 { 31 if(mp.size()>=5) return; 32 mp[v[2][j]]++; 33 if(mp[v[2][j]]>=2) 34 cnt++,mp.erase(v[2][j]); 35 ans = max(cnt,ans); 36 dfs(i,j+1,k,w); 37 if(!mp.count(v[2][j])) cnt--,mp[v[2][j]] = 1; 38 else mp.erase(v[2][j]); 39 } 40 if(k<n) 41 { 42 if(mp.size()>=5) return; 43 mp[v[3][k]]++; 44 if(mp[v[3][k]]>=2) 45 cnt++,mp.erase(v[3][k]); 46 ans = max(cnt,ans); 47 dfs(i,j,k+1,w); 48 if(!mp.count(v[3][k])) cnt--,mp[v[3][k]] = 1; 49 else mp.erase(v[3][k]); 50 } 51 if(w<n) 52 { 53 if(mp.size()>=5) return; 54 mp[v[4][w]]++; 55 int t = v[4][w]; 56 if(mp[v[4][w]]>=2) 57 cnt++,mp.erase(v[4][w]); 58 ans = max(cnt,ans); 59 dfs(i,j,k,w+1); 60 if(!mp.count(v[4][w])) cnt--,mp[v[4][w]] = 1; 61 else mp.erase(v[4][w]); 62 } 63 } 64 int main() 65 { 66 while(scanf("%d",&n)!=EOF&&n) 67 { 68 memset(st,0,sizeof st); 69 mp.clear(); ans =0; cnt = 0; 70 for(int i=1;i<=4;i++) v[i].clear(); 71 for(int i=1;i<=n;i++) 72 for(int j=1;j<=4;j++) 73 { 74 int x; scanf("%d",&x); 75 v[j].push_back(x); 76 } 77 dfs(0,0,0,0); 78 printf("%d\n",ans); 79 } 80 return 0; 81 }