HDU 2440、HDU 3694多边形费马点

1、http://acm.hdu.edu.cn/showproblem.php?pid=2440   按照题意知道是一个简单的多边形即凸包,但给出的点并没有按照顺序的,所以需要自己先求出凸包,然后在用随机淬火求费马点。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<algorithm>
#include<ctime>
using namespace std;
#define eps 1e-10

int Fabs(double d)
{
    if(fabs(d)<eps) return 0;
    else return d>0?1:-1;
}

struct point
{
    double x,y;
}p[105],sta[105];
int oper[8][2]={0,1,0,-1,-1,0,1,0,1,1,1,-1,-1,1,-1,-1},top;

double x_multi(point p1,point p2,point p3)
{
    return (p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y);
} 

double Dis(point p1,point p2)
{
    return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}

bool cmp(point a,point b)
{
    if(Fabs(x_multi(p[0],a,b))>0) return 1;
    if(Fabs(x_multi(p[0],a,b))<0) return 0;
    if(Fabs(Dis(p[0],a)-Dis(p[0],b))<0)
        return 1;
    return 0;
}

void Graham(int n)
{
    int i,k=0,tot;
    for(i=1;i<n;i++)
        if((p[i].y<p[k].y)||((p[i].y==p[k].y)&&(p[i].x<p[k].x)))
            k=i;
    swap(p[0],p[k]);
    sort(p+1,p+n,cmp);

    tot=1;
    for(i=2;i<n;i++)
        if(Fabs(x_multi(p[i],p[i-1],p[0])))
            p[tot++]=p[i-1];
    p[tot++]=p[n-1];

    sta[0]=p[0],sta[1]=p[1];
    i=top=1;
    for(i=2;i<tot;i++)
    {
        while(top>=1&&Fabs(x_multi(p[i],sta[top],sta[top-1]))>=0)
        {
            if(top==0) break;
            top--;
        }
        sta[++top]=p[i];
    }
}

double allDis(int n,point f)
{
    double sum=0.0;
    int i;
    for(i=0;i<n;i++)
        sum+=Dis(sta[i],f);
    return sum;
}

point fermat(int n) //求费马点
{
    double step=0;
    int i,j;
    for(i=0;i<n;i++)
        step+=fabs(sta[i].x)+fabs(sta[i].y);
    point f;
    f.x=0,f.y=0;
    for(i=0;i<n;i++)
        f.x+=sta[i].x,f.y+=sta[i].y;
    f.x/=n,f.y/=n;
    point t;
    while(step>eps)
    {
        for(i=0;i<8;i++)
        {
            t.x=f.x+oper[i][0]*step;
            t.y=f.y+oper[i][1]*step;
            if(allDis(n,t)<allDis(n,f))
                f=t;
        }
        step/=2;
    }
    return f;
}

int main()
{
    int t,n,i;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=0;i<n;i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        Graham(n);
        point ans=fermat(top+1);
        printf("%.0lf\n",allDis(top+1,ans));
        if(t>0) puts("");
    }
    return 0;
}

2、http://acm.hdu.edu.cn/showproblem.php?pid=3694 //求一个四边形的费马点,wrong了n次网上到处查才知道此题非常严谨,卡随机淬火算法。并且给出的四边形并不一定是凸四边形,所以需要讨论,如果是凸四边形,按照四边形的特性费马点就是对角线的交点,如果是凹的就是其中某一个顶点。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<algorithm>
#include<ctime>
using namespace std;
#define eps 1e-8

int Fabs(double d)
{
    if(fabs(d)<eps) return 0;
    else return d>0?1:-1;
}

struct point
{
    double x,y;
}p[10],sta[10];
int oper[8][2]={0,1,0,-1,-1,0,1,0,1,1,1,-1,-1,1,-1,-1},top;

double x_multi(point p1,point p2,point p3)
{
    return (p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y);
} 

double Dis(point p1,point p2)
{
    return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}

bool cmp(point a,point b)
{
    if(Fabs(x_multi(p[0],a,b))>0) return 1;
    if(Fabs(x_multi(p[0],a,b))<0) return 0;
    if(Fabs(Dis(p[0],a)-Dis(p[0],b))<0)
        return 1;
    return 0;
}

void Graham(int n)
{
    int i,k=0,tot;
    for(i=1;i<n;i++)
        if((p[i].y<p[k].y)||((p[i].y==p[k].y)&&(p[i].x<p[k].x)))
            k=i;
    swap(p[0],p[k]);
    sort(p+1,p+n,cmp);

    /*tot=1;//下面直接用顶点个数判断是否为凸包,所以这里不去共线点
    for(i=2;i<n;i++)
        if(Fabs(x_multi(p[i],p[i-1],p[0])))
            p[tot++]=p[i-1];
    p[tot++]=p[n-1];*/

    sta[0]=p[0],sta[1]=p[1];
    i=top=1;
    for(i=2;i<n;i++)
    {
        while(top>=1&&Fabs(x_multi(p[i],sta[top],sta[top-1]))>=0)
        {
            if(top==0) break;
            top--;
        }
        sta[++top]=p[i];
    }
}

/*double allDis(int n,point f)
{
    double sum=0.0;
    int i;
    for(i=0;i<n;i++)
        sum+=Dis(p[i],f);
    return sum;
}

point fermat(int n)
{
    double step=0;
    int i,j;
    for(i=0;i<n;i++)
        step+=fabs(sta[i].x)+fabs(sta[i].y);
    point f;
    f.x=0,f.y=0;
    for(i=0;i<n;i++)
        f.x+=sta[i].x,f.y+=sta[i].y;
    f.x/=n,f.y/=n;
    point t;
    while(step>1e-10)
    {
        for(i=0;i<8;i++)
        {
            t.x=f.x+oper[i][0]*step;
            t.y=f.y+oper[i][1]*step;
            if(allDis(n,t)<allDis(n,f))
                f=t;
        }
        step/=2;
    }
    return f;
}
*/
int main()
{
    int i,j;
    while(~scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&p[0].x,&p[0].y,&p[1].x,&p[1].y,&p[2].x,&p[2].y,&p[3].x,&p[3].y))
    {
        if(p[0].x==-1&&p[0].y==-1&&p[1].x==-1&&p[1].y==-1&&p[2].x==-1&&p[2].y==-1&&p[3].x==-1&&p[3].y==-1)
            break;
        Graham(4);
        double ans;
        if(top==3)
            ans=Dis(sta[0],sta[2])+Dis(sta[1],sta[3]);//凸四边形就直接取对角线交点
        else
        {
            ans=1e50;
            double sum=0;
            for(i=0;i<4;i++)
            {
                sum=0.0;
                for(j=0;j<4;j++)
                    if(i!=j)
                        sum+=Dis(p[i],p[j]);
                 ans=min(sum,ans);
            }
        }
        printf("%.4lf\n",ans);
    }
    return 0;
}
时间: 2024-10-15 05:21:59

HDU 2440、HDU 3694多边形费马点的相关文章

HDU 1098 Ignatius&#39;s puzzle 费马小定理+扩展欧几里德算法

题目大意: 给定k,找到一个满足的a使任意的x都满足 f(x)=5*x^13+13*x^5+k*a*x 被65整除 推证: f(x) = (5*x^12 + 13 * x^4 + ak) * x 因为x可以任意取 那么不能总是满足 65|x 那么必须是 65 | (5*x^12 + 13 * x^4 + ak) 那么就是说 x^12 / 13 + x^4 / 5 + ak / 65 正好是一个整数 假设能找到满足的a , 那么将 ak / 65 分进x^12 / 13 + x^4 / 5中得到

hdu 4549 (矩阵快速幂+费马小定理)

题意:已知F0=a,F1=b,Fn=Fn-1*Fn-2,给你a,b,n求Fn%1000000007的值 思路:我们试着写几组数 F0=a F1=b F2=a*b F3=a*b2 F4=a2*b3 F5=a3*b5 我们发现a,b的系数其实是斐波那契数列,我们只需用矩阵快速幂求出相应系数就行,但是 这个系数随着增长会特别大,这时我们需要利用费马小定理进行降幂处理 费马小定理 ap-1≡1(mod p) 代码: #include <iostream> #include <cmath>

HDU 5793 A Boring Question (费马小定理) ---2016杭电多校联合第六场

A Boring Question Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 156    Accepted Submission(s): 72 Problem Description There are an equation.∑0≤k1,k2,?km≤n∏1?j<m(kj+1kj)%1000000007=?We define t

HDU 4704 Sum (隔板原理 + 费马小定理)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4704 题意: 给定一个数n 将其分解,Si 表示将n拆成i个数的方案数 求sum( si ) 1<=i<=n; 分析: 隔板原理,  n个木棍,n-1个缝, 分成1份则是C(n-1,0); 分成2份则是C(n-1,1); 分成3份则是C(n-1,2); ... 分成n份则是C(n-1,n-1); ans = sum( C(n-1,i) )   (0<=i<=n-1) =2^(n-1)

HDU 3694 Fermat Point in Quadrangle (费马定理求四边形的费马点)

题意:给你四个点,找出一个点到四个点的距离最小 四边形的费马点:凸边形是两对角线的交点,凹边形式凹点. PS: 三角形的费马点: 1.若三角形3个内角均小于120°,那么3条距离连线正好三等分费马点所在的周角,即该点所对三角形三边的张角相等,均为120°.所以三角形的费马点也称为三角形的等角中心. 2.若三角形有一内角大于等于120°,则此钝角的顶点就是距离和最小的点. #include<stdio.h> #include<string.h> #include<stdlib.

hdu 4549 M斐波那契数列(快速幂 矩阵快速幂 费马小定理)

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=4549: 题目是中文的很容易理解吧.可一开始我把题目看错了,这毛病哈哈. 一开始我看错题时,就用了一个快速幂来解,不用说肯定wa,看题目的通过率也不高,我想会不会有啥坑啊.然而我就是那大坑,哈哈. 不说了,直接说题吧,先讨论k=1,2,3;时的解.这应该会解吧,不多说了: 从第四项开始f(4)=a^1+b^2;f(5)=a^2+b^3;f(6)=a^3+b^5......; 看出来了吧,a上的指数成斐波

HDU 4704 Sum( 费马小定理 )

HDU 4704 Sum( 费马小定理 ) 理解能力果然拙计,,题目看半天没懂什么意思. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; #define MOD 1000000007 char str[100010]; LL fast_mod( LL a, int b) { LL res = 1; while( b )

hdu 4704 Sum (费马小定理+快速幂)

//(2^n-1)%mod //费马小定理:a^n ≡ a^(n%(m-1)) * a^(m-1)≡ a^(n%(m-1)) (mod m) # include <stdio.h> # include <algorithm> # include <string.h> # define mod 1000000007 using namespace std; __int64 pow(__int64 n) { __int64 p=1,q=2; while(n) { if(n%

2014多校第一场 I 题 || HDU 4869 Turn the pokers(费马小定理+快速幂模)

题目链接 题意 : m张牌,可以翻n次,每次翻xi张牌,问最后能得到多少种形态. 思路 :0定义为反面,1定义为正面,(一开始都是反), 对于每次翻牌操作,我们定义两个边界lb,rb,代表每次中1最少时最少的个数,rb代表1最多时的个数.一张牌翻两次和两张牌翻一次 得到的奇偶性相同,所以结果中lb和最多的rb的奇偶性相同.如果找到了lb和rb,那么,介于这两个数之间且与这两个数奇偶性相同的数均可取到,然后在这个区间内求组合数相加(若lb=3,rb=7,则3,5,7这些情况都能取到,也就是说最后的