https://codeforces.com/contest/1455/problem/E
题意:T组,每组给4个点(可上下左右移动),找到一个正方形,使得这四个点到该正方形四个顶点的步数最小。
题解:思维题,隐藏条件是最优解情况下正方形边长必为两个点的横纵标或纵坐标之差,在草稿纸上画出几种极端情况可简易证明。
因为最终四个点要组成的是一个正方形,所以固定住左下角的点,用左上角点的纵坐标-边长,右上角点的横纵坐标-边长,右下角点的横坐标-边长,此时相当于四个顶点的终点都是一个点(注意不一定是移动到左下角点为最优),对四个点的横纵坐标分别排序,然后依次减去第二大或者第三大的数求和得到每种情况的步数(共有12*24种情况)。
之后就是暴力枚举正方形边长和四个点全排列的位置,复杂度是12*24*4,t是1e4,复杂度是够的,实现起来也没什么难度,主要还是隐藏条件难发现,不知道为什么过了三天这道题还是只有不到200的人补了。
#include<bits/stdc++.h> #include<vector> #include<map> #include<queue> #define LL long long #define inf 0x3f3f3f3f #define MOD 1000000007 #define stree SegTree[root] #define lson SegTree[root << 1] #define rson SegTree[root << 1 | 1] using namespace std; const LL INF = 0x3f3f3f3f3f3f3f3f; const int N = 100005; struct node { LL x, y; }a[20]; LL xx[10], yy[10], p[10], d[20]; int main() { LL T, n, x; cin>>T; for(LL i = 1;i <= 4;i++) p[i] = i; while(T--) { LL cnt = 0, ans = INF; for(LL i = 1;i <= 4;i++) { scanf("%d%d", &a[i].x, &a[i].y); for(LL j = 1;j < i;j++) { d[++cnt] = abs(a[i].x-a[j].x); d[++cnt] = abs(a[i].y-a[j].y); } } do { for(LL i = 1;i <= cnt;i++) { LL tem = 0; for(LL j = 1;j <= 4;j++) { xx[j] = a[p[j]].x; yy[j] = a[p[j]].y; } yy[2]-=d[i]; xx[3]-=d[i], yy[3]-=d[i]; xx[4]-=d[i]; sort(xx+1, xx+5); sort(yy+1, yy+5); for(LL i = 1;i <= 4;i++) { tem += abs(xx[i]-xx[3]) + abs(yy[i]-yy[3]); } ans = min(ans, tem); //prLLf("ans = %d ", ans); } }while(next_permutation(p+1, p+5)); printf("%lld ", ans); } return 0; }