HDU 5365 Run(大水题)

大致题意:

8*8的整点格子,输入16个整点,求多少种点的集合可以组成正3,正4,5,6边形


思路:sb题啊...整点格子组成不了n !=4的所有正多边形,只要判是否能组成正方形就可以了
这里有个优美的无穷递降的证明:http://www.zhihu.com/question/25304120


而我是枚举所有点的集合判断是否能组成正多边形的蠢方法= =,先用凸包对点排个序,然后判各点距离相等和用余弦定理判个顶角相等.....


//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>
#include <bitset>
#include <algorithm>
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define reveach(i, v) for (__typeof((v).rbegin()) i = (v).rbegin(); i != (v).rend(); ++ i)
#define REP(i,n) for ( int i=1; i<=int(n); i++ )
#define rep(i,n) for ( int i=0; i<int(n); i++ )
using namespace std;
typedef long long ll;
#define X first
#define Y second
typedef pair<int,int> pii;

template <class T>
inline bool RD(T &ret) {
    char c; int sgn;
    if (c = getchar(), c == EOF) return 0;
    while (c != '-' && (c<'0' || c>'9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return 1;
}
template <class T>
inline void PT(T x) {
    if (x < 0) {
        putchar('-');

        x = -x;
    }
    if (x > 9) pt(x / 10);
    putchar(x % 10 + '0');
}

const int N = 25;
pii poi[N];
int a[1<<20];
int top;

inline int cal(int x){
        int ans = 0;
        while(x) ans += x&1, x >>= 1;
        return ans;
}
int b[10];
int dis(pii &a,pii &b){
        int A = a.X-b.X;
        int B = a.Y-b.Y;
        return A*A+B*B;
}

pii tmp[10];


bool cmp(pii a,pii b)
{
    if(a.X==b.X)return a.Y<b.Y;
    return a.X<b.X;
}
int cross(pii a,pii b,pii c)//向量积
{
    return (a.X-c.X)*(b.Y-c.Y)-(b.X-c.X)*(a.Y-c.Y);
}
pii res[10];
int convex(int n)//求凸包上的点
{
    sort(tmp,tmp+n,cmp);
    int m=0,i,k;
     //求得下凸包,逆时针
    //已知凸包点m个,如果新加入点为i,则向量(m-2,i)必定要在(m-2,m-1)的逆时针方向才符合凸包的性质
   //若不成立,则m-1点不在凸包上。
    for(i=0;i<n;i++)
    {
        while(m>1&&cross(res[m-1],tmp[i],res[m-2])<=0)m--;
        res[m++]=tmp[i];
    }
    k=m;
    //求得上凸包
    for(i=n-2;i>=0;i--)
    {
        while(m>k&&cross(res[m-1],tmp[i],res[m-2])<=0)m--;
        res[m++]=tmp[i];
    }
    if(n>1)m--;//起始点重复。
    return m;
}

int jiao(pii a,pii b,pii c){
        return (b.X-a.X)*(c.X-a.X)+(b.Y-a.Y)*(c.Y-a.Y);
}
int t[10];
bool judge(int x){
        int c = 0;
        for(int i = 0 ; (1<<i) <= x; i++){
                if( x&(1<<i) )
                        tmp[c++] = poi[i+1];
        }
        int n = convex(c);
        if( n != c) return false;
        REP(i,c) tmp[i] = res[i-1];
        tmp[0] = tmp[c],tmp[c+1] = tmp[1];
        REP(i,c)
                b[i] = dis(tmp[i],tmp[i+1]);
        for(int i = 2; i <= c;i++){
                if( b[i] != b[i-1]) return false;
        }
        REP(i,c) t[i] = jiao(tmp[i],tmp[i-1],tmp[i+1]);
        for(int i = 2; i <= c ;i++)
                if( t[i] != t[i-1]) return false;
        return true;
}
int main(){
        rep(i,1<<20) {
                int x = cal(i);
                if( x == 3 || x == 4 || x== 5 || x== 6) a[++top] = i;
        }
        int n;
        while(~scanf("%d",&n)){
                REP(i,n) scanf("%d%d",&poi[i].X,&poi[i].Y);
                int ans = 0;
                REP(i,top){
                        if( a[i] > (1<<n) ) break;
                        ans += judge(a[i]);
                }
                printf("%d\n",ans);
        }

}


你可能感兴趣的:(HDU 5365 Run(大水题))