Codeforces Round #271 (Div. 2) C. Captain Marmot

题目: LINK


给定4个点 和每个点可以围绕转动的中心点的坐标, 每个点可以逆时针每次转动90度, 问4个点是否可以通过转动后的位置组成一个正方形,如果可以输出最少的转动次数和, 否则-1.


思路没有什么难的, 暴力直接做,O(4^4*n); 
注意两点:1, 结果中间坐标距离的平方会超int, 最大 (4e4)^2 * 2 ,开始竟然算的是max = 8e8.不要吝惜用LL
2, 判断四个点是否可以组成面积非0的正方形时, 注意四个点不要有相同的点。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std; 
#define INF 1000000000
typedef __int64 LL; 
#define N 111
LL n; 
struct node {
    LL a, b, x, y; 
}p[4*N]; 
struct no {
    LL x[6], y[6]; 
}pp[4*N]; 
map<LL , LL> mm; 
void sol(LL id) {
    pp[id].x[0] = p[id].x - p[id].a; 
    pp[id].y[0] = p[id].y - p[id].b; 
    for(LL i = 1; i <= 3; i++) {
    	pp[id].x[i] = -pp[id].y[i-1];
   		pp[id].y[i] = pp[id].x[i-1]; 
    }
    for(LL i = 0; i <= 3; i++) {
        pp[id].x[i] += p[id].a; 
        pp[id].y[i] += p[id].b; 
    }
}
LL right(LL x[], LL y[]) {
    mm.clear(); 
    for(LL i = 1; i <= 4; i++) {
        for(LL j = i+1; j <= 4; j++) {
            if(x[i] == x[j] && y[i] == y[j]) return 0; // notice
            LL dis = (x[i] - x[j]) *(x[i] - x[j]) + (y[i] - y[j] )*(y[i] - y[j]); 
            mm[dis] ++; 
        }
    }
    LL dd[4], cc[4], cou = 0; 
    map<LL , LL> ::iterator it ;
    for(it = mm.begin(); it != mm.end(); it++) {
        cou ++; 
        if(cou >= 3) return 0; 
        dd[cou] = it->second; 
        cc[cou] = it->first; 
    }
    if(cou == 1) return 0; 
    if( (dd[1] == 2*dd[2]  && cc[1]* 2 == cc[2])|| (2*dd[1] == dd[2] && cc[1] == 2*cc[1])) return 1; 
    return 0; 
}
LL test(LL add, LL s[]) {
    LL xz[6], yz[6]; 
    for(int i = 1; i <= 4; i++) {
    	xz[i] = pp[add+i].x[s[i]]; 
    	yz[i] = pp[add+i].y[s[i]]; 
    }
   	return right(xz, yz); 
}
int main() 
{
    scanf("%I64d", &n); 
    for(LL i = 1; i <= 4 * n; i++)  
    	scanf("%I64d%I64d%I64d%I64d", &p[i].x, &p[i].y, &p[i].a, &p[i].b);
    for(LL i = 1; i <= 4*n; i ++) sol(i); 
    LL sel[10]; 
    for(LL i = 1; i <= n; i++){
        LL add = (i-1)*4;
        LL out = INF; 
        for(LL sta = 0; sta < 256; sta ++) {
            LL tmp = sta; 
            LL yao = 0; 
            for(LL j = 1; j <= 4; j++) {
                LL now = tmp % 4; 
                yao += now; 
                sel[j] = now; 
                tmp /= 4; 
            }
            LL gg = test(add, sel); 
            if(gg) out = min(out, yao); 
        }
        if(out >= INF) puts("-1"); 
        else printf("%I64d\n", out); 
    }
    return 0; 
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值