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


题意:给你四个点,找出一个点到四个点的距离最小


四边形的费马点:凸边形是两对角线的交点,凹边形式凹点。


PS:

三角形的费马点:

1.若三角形3个内角均小于120°,那么3条距离连线正好三等分费马点所在的周角,即该点所对三角形三边的张角相等,均为120°。所以三角形的费马点也称为三角形的等角中心

2.若三角形有一内角大于等于120°,则此钝角的顶点就是距离和最小的点。


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<string>
#include<queue>
#include<map>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int kind = 26;
const int maxn = 250*1000; //注意RE,单词长度*单词个数
const int M = 5100000;
struct Point    
{    
    double x,y;    
};    
//小于0,说明向量p0p1的极角大于p0p2的极角    
double multiply(Point p1,Point p2,Point p0)    
{    
    return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.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)));    
}    
void Graham_scan(Point PointSet[],Point ch[],int n,int &len)    
{    
    int i,j,k=0,top=2;    
    Point tmp;    
    
    //找到最下且偏左的那个点    
    for(i=1;i<n;i++)    
        if ((PointSet[i].y<PointSet[k].y)||((PointSet[i].y==PointSet[k].y)&&(PointSet[i].x<PointSet[k].x)))    
            k=i;    
    //将这个点指定为PointSet[0]    
    tmp=PointSet[0];    
    PointSet[0]=PointSet[k];    
    PointSet[k]=tmp;    
    
    //按极角从小到大,距离偏短进行排序    
    for (i=1;i<n-1;i++)    
    {    
        k=i;    
        for (j=i+1;j<n;j++)    
            if( (multiply(PointSet[j],PointSet[k],PointSet[0])>0)    
                ||((multiply(PointSet[j],PointSet[k],PointSet[0])==0)    
                    &&(dis(PointSet[0],PointSet[j])<dis(PointSet[0],PointSet[k]))) )    
                k=j;//k保存极角最小的那个点,或者相同距离原点最近    
        tmp=PointSet[i];    
        PointSet[i]=PointSet[k];    
        PointSet[k]=tmp;    
    }    
    //第三个点先入栈    
    ch[0]=PointSet[0];    
    ch[1]=PointSet[1];    
    ch[2]=PointSet[2];    
    //判断与其余所有点的关系    
    for (i=3;i<n;i++)    
    {    
        //不满足向左转的关系,栈顶元素出栈    
        while(multiply(PointSet[i],ch[top],ch[top-1])>=0) top--;    
        //当前点与栈内所有点满足向左关系,因此入栈.    
        ch[++top]=PointSet[i];    
    }    
    len=top+1;    
}    
Point intersection(Point u1,Point u2,Point v1,Point v2)
{
    Point ret=u1;
    double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))
        /((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));
    ret.x+=(u2.x-u1.x)*t;
    ret.y+=(u2.y-u1.y)*t;
    return ret;
}
Point p[4],ch[4],point;
int len;
int main()
{
    int x1, y1, x2, y2, x3, y3, x4, y4;
    int x[4],y[4];
    while(scanf("%lf%lf",&p[0].x,&p[0].y))
    {
        int flag=0;
        if(p[0].x!=-1||p[0].y!=-1) flag=1;
        for(int i=1;i<4;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
            if(p[i].x!=-1||p[i].y!=-1)
                flag=1;
        }
        if(!flag) break;
        double minn=10000000,ans=0.0;
        int k=0;
        Graham_scan(p,ch,4,len);
        for(int i=0;i<4;i++)
        {
            ans=0.0;
            for(int j=0;j<4;j++)
            {
                ans+=dis(p[i],p[j]);
            }
            if(ans<minn)
                minn=ans;
        }
        point=intersection(p[0],p[2],p[1],p[3]);
        //printf("%lf %lf\n",point.x,point.y);
        ans=0.0;
        for(int i=0;i<4;i++)
        {
            ans+=dis(p[i],point);
        } 
        printf("%.4lf\n",min(minn,ans));
    }
    return 0;
}
/*
0 0 0 0 1 0 0 1
0 0 1 1 1 0 0 1
1 1 1 1 1 1 1 1
-1 -1 -1 -1 -1 -1 -1 -1
*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于 HDU4992 所有原根的问题,我可以给出以下解答: 1. 首先,我们需要知道什么是原根。原根是指模 n 意义下,所有与 n 互质的数 a 的最小正整数 k 次幂对 n 取模的值覆盖了所有与 n 互质的数。简单来说,就是如果一个数 a 是模 n 意义下的原根,那么 a 的任何正整数次幂对 n 取模的值都不相同,且能覆盖所有与 n 互质的数。 2. 为了模 n 意义下的所有原根,我们需要先出与 n 互质的数的个数 phi(n)。phi(n) 可以使用欧拉函数出。 3. 然后,我们需要枚举模 n 意义下的所有数,判断它是否是原根。具体来说,对于每个 a,我们需要判断 a 的每个小于 phi(n) 的正整数次幂对 n 取模的值是否都不相同,且能覆盖所有与 n 互质的数。如果是,那么 a 就是模 n 意义下的原根。 4. 代码实现可以参考以下 Java 代码: ``` import java.util.*; public class Main { static int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } static int phi(int n) { int res = n; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { res = res / i * (i - 1); while (n % i == 0) { n /= i; } } } if (n > 1) { res = res / n * (n - 1); } return res; } static int pow(int a, int b, int mod) { int res = 1; while (b > 0) { if ((b & 1) != 0) { res = res * a % mod; } a = a * a % mod; b >>= 1; } return res; } static boolean check(int a, int n, int phi) { for (int i = 1, j = pow(a, i, n); i <= phi; i++, j = j * a % n) { if (j == 1) { return false; } } return true; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { int n = scanner.nextInt(); int phi = phi(n); List<Integer> ans = new ArrayList<>(); for (int i = 1; i < n; i++) { if (gcd(i, n) == 1 && check(i, n, phi)) { ans.add(i); } } Collections.sort(ans); for (int x : ans) { System.out.print(x + " "); } System.out.println(); } } } ``` 其中,gcd 函数用于最大公约数,phi 函数用于欧拉函数,pow 函数用于快速幂模,check 函数用于判断一个数是否是原根。在主函数中,我们依次读入每个 n,出 phi(n),然后枚举模 n 意义下的所有数,判断它是否是原根,将所有原根存入一个 List 中,最后排序输出即可。 希望我的回答能够帮到你,如果你有任何问题,欢迎随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值