看了题目,因为n很小,最多20,第一反应是状压dp,首先预处理可能构成正方形的状态集合,然后背包算出来就行了,但是考量了一下复杂度,dp的状态是1<<20,然后当20个点是能构成的正方形的四个点,然后每个点重复5次,则能构成正方形的状态集合个数是4*4*4*4=256,dp转移的极限运算次数大概就是2亿,还是多组数据,果断换思路。不过下来发现很多都是状压dp过的,看来数据应该没有故意卡这种极限情况。
这里用dfs来写会更快,dfs之前,先将点按照y从小到大,x从小到大的时候排序,则dfs处理这个点的时候,这个点如果能构成,则一定是正方形的左下点,然后在枚举y值相同的,x更大的点,根据这两个点就能算出其他两个点的位置,然后回溯就行。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int maxn = 22; 6 int n, x[maxn], y[maxn], a[maxn], ans, vis[maxn]; 7 int mp[210][210]; 8 int cmp(int i, int j) { 9 if (y[i] != y[j]) 10 return y[i] < y[j]; 11 return x[i] < x[j]; 12 } 13 void dfs(int dep) { 14 if (dep * 4 > ans) 15 ans = dep << 2; 16 for (int i = 0; i < n; ++i) 17 if (!vis[i]) 18 for (int j = i + 1; j < n; ++j) 19 if (!vis[j]) { 20 int ii = a[i], jj = a[j]; 21 if (y[ii] == y[jj] && x[ii] < x[jj]) { 22 int d = x[jj] - x[ii], k, l; 23 for (k = j + 1; k < n && !(x[a[k]] == x[ii] && y[a[k]] == y[ii] + d && !vis[k]); ++k); 24 for (l = j + 1; l < n && !(x[a[l]] == x[jj] && y[a[l]] == y[ii] + d && !vis[l]); ++l); 25 if (k < n && l < n) { 26 vis[i] = vis[j] = vis[k] = vis[l] = 1; 27 dfs(dep + 1); 28 vis[i] = vis[j] = vis[k] = vis[l] = 0; 29 } 30 } 31 } 32 } 33 int main() { 34 while (~scanf("%d", &n) && n != -1) { 35 memset(mp, 0, sizeof(mp)); 36 for (int i = 0; i < n; ++i) { 37 scanf("%d%d", &x[i], &y[i]); 38 a[i] = i; 39 ++mp[x[i]][y[i]]; 40 } 41 sort(a, a + n, cmp); 42 ans = 0; 43 memset(vis, 0, sizeof(vis)); 44 dfs(0); 45 printf("%d\n", ans); 46 } 47 return 0; 48 }