• 数论模板


    [toc]

    闲的无聊翻了一下快爆了的E盘,发现里面有不少“好东西“”,一堆关于数论的课件,所以就整理一下常见的数论模板。虽然我不会数论,但至少整理一下可以知道以后学什么(顺便水篇博客

    欧几里德:

    #include<iostream>
    using namespace std;
    int hcf(int a,int b)       
    {
        int r=0;
        while(b!=0)
        {
            r=a%b;
            a=b;
            b=r;
        }
        return(a);
    } 
    lcd(int u,int v,int h) //u=a,v=b,h为最小公约数=hcf(a,b);
    {
        return(u*v/h);
    }
    int main()
    {
    
           int a,b,x,y;
           cin>>a>>b;
           x=hcf(a,b);
           y=lcd(a,b,x);
           cout<<x<<" "<<y<<endl;
           return 0;
    
    }
    

    扩展欧几里德

    #include <iostream>
    using namespace std;
    __int64 ext_euclid(__int64 a,__int64 b, __int64 &x, __int64 &y)
    {
        int t;
        __int64 d;
        if (b==0) {x=1;y=0;return a;}
        d=ext_euclid(b,a %b,x,y);
        t=x;
        x=y;
        y=t-a/b*y;
        return d;
    }
    void modular_equation(__int64 a,__int64 b,__int64 c)//ax = b(mod n)
    {
        __int64 d;
        __int64 x,y;
        d = ext_euclid(a,b,x,y);
        if ( c % d != 0 )
            printf("No answer
    ");
        else
        {
            x = (x * c/d) % b ;// 第一次求出的x ; 
            __int64 t = b/d;
            x = (x%t + t)%t;
            printf("%I64d
    ",x);//最小的正数的值
            for (int i=0;i<d;i++)
                printf("The %dth answer is : %ld
    ",i+1,(x+i*(b/d))%b); //所有的正数值
        }
    }
    /*函数返回值为gcd(a,b),并顺带解出ax+by=gcd(a,b)的一个解x,y,
    
      对于不定方程ax+by=c的通解为:
    
      x=x*c/d+b/d*t
    
      y=y*c/d+a/d*t
    
    当c%gcd(a,b)!=0时,不定方程无解.*/
    
    

    中国剩余定理:

    #include <iostream>
    using namespace  std;
     int ext_euclid(int a,int b,int &x,int &y)  //求gcd(a,b)=ax+by
    {
        int t,d;
        if (b==0) {x=1;y=0;return a;}
        d=ext_euclid(b,a %b,x,y);
        t=x;
        x=y;
        y=t-a/b*y;
        return d;
    }
    int China(int W[],int B[],int k)   //W为按多少排列,B为剩余个数   W>B  K为组数
    {
        int i;
        int d,x,y,a=0,m,n=1;
        for (i = 0;i<k;i++)
            n *= W[i];
        for (i=0;i<k;i++)
        {
            m=n/W[i];
            d=ext_euclid(W[i],m,x,y);
            a=(a+y*m*B[i])%n;
        }
        if (a>0)
            return a;
        else
            return(a+n);
    }
    int main()
    {
        int B[100],W[100];                                求
        int k ;                                           a = 2( mod 5 )
        cin >> k ;                                        a = 3( mod 13)
        for(int i = 0 ; i < k ;i++)                            的解
        {                                               2
            cin >> W[i];                                  5 2
            cin >> B[i];                                   13 3    
        }                                               输出 42
        cout<<China(W,B,k)<<endl;
        return 0;
    }

    欧拉函数:

    求小于n的所有欧拉数

    #include <iostream>
    using namespace std;
    int phi[1000];     //数组中储存每个数的欧拉数
    
    void genPhi(int n)//求出比n小的每一个数的欧拉数(n-1的)
    {
        int i, j, pNum = 0 ;
        memset(phi, 0, sizeof(phi)) ;
        phi[1] = 1 ;
        for(i = 2; i < n; i++)
        {
            if(!phi[i])
            {
                for(j = i; j < n; j += i)
                {
                    if(!phi[j])
                        phi[j] = j;
                    phi[j] = phi[j] / i * (i - 1);
                }
            }
        }
    }
    求n的欧拉数
    int eular(int n)
    {
        int ret=1,i;
        for (i=2;i*i<=n;i++)
            if (n%i==0)
            {
                n/=i,ret*=i-1;
                while (n%i==0)
                    n/=i,ret*=i;
            }
            if (n>1)
                ret*=n-1;
            return ret;    //n的欧拉数
    }

    行列式计算:

    #include <iostream>
    using namespace std;
    int js(int s[100][100],int n) 
    {
        int z,j,k,r,total=0; 
        int b[100][100];  /*b[N][N]用于存放,在矩阵s[N][N]中元素s[0]的余子式*/ 
        if(n>2)
        {
            for(z=0;z<n;z++) 
            {
                for(j=0;j<n-1;j++) 
            for(k=0;k<n-1;k++) 
                if(k>=z) 
                        b[j][k]=s[j+1][k+1];  
                else 
                    b[j][k]=s[j+1][k]; 
                if(z%2==0) 
                    r=s[0][z]*js(b,n-1); /*递归调用*/ 
                else 
                    r=(-1)*s[0][z]*js(b,n-1); 
                total=total+r; 
            } 
        } 
        else if(n==2)
            total=s[0][0]*s[1][1]-s[0][1]*s[1][0]; 
        return total; 
    }

    排列:

    long A(long n,long m)   //n>m
    {
        long a=1;
        while(m!=0)  {a*=n;n--;m--;}
        return a;
    } 

    组合:

    long C(long n,long m)     //n>m
    {
        long i,c=1;
        i=m;
        while(i!=0)   {c*=n;n--;i--;}
    while(m!=0)  {c/=m;m--;} 
    return c; 
    }

    大数乘大数:

    #include <iostream>
    #include <string>
    using namespace std;
    char a[1000],b[1000],s[10000];
    void mult(char a[],char b[],char s[])     //a被乘数,b乘数,s为积
    {
        int i,j,k=0,alen,blen,sum=0,res[65][65]={0},flag=0;
        char result[65];
        alen=strlen(a);blen=strlen(b); 
        for (i=0;i<alen;i++)
        for (j=0;j<blen;j++) res[i][j]=(a[i]-'0')*(b[j]-'0');
        for (i=alen-1;i>=0;i--)
            {
                for (j=blen-1;j>=0;j--) sum=sum+res[i+blen-j-1][j];
                result[k]=sum%10;
                k=k+1;
                sum=sum/10;
            }
        for (i=blen-2;i>=0;i--)
            {
                for (j=0;j<=i;j++) sum=sum+res[i-j][j];
                result[k]=sum%10;
                k=k+1;
                sum=sum/10;
            }
        if (sum!=0) {result[k]=sum;k=k+1;}
        for (i=0;i<k;i++) result[i]+='0';
        for (i=k-1;i>=0;i--) s[i]=result[k-1-i];
        s[k]='';
        while(1)
            {
            if (strlen(s)!=strlen(a)&&s[0]=='0') 
                strcpy(s,s+1);
            else
                break;
            }
    }
    int main()
    {
        cin>>a>>b;
        mult(a,b,s);
        cout<<s<<endl;
        return 0;
    }

    大数乘小数:

    #include <iostream>
    using namespace std;
    char a[100],t[1000];
    void mult(char c[],int m,char t[])  // c为大数,m<=10,t为积
    {
        int i,l,k,flag,add=0;
        char s[100];
        l=strlen(c);
        for (i=0;i<l;i++)
            s[l-i-1]=c[i]-'0'; 
        for (i=0;i<l;i++)
        {
            k=s[i]*m+add;
            if (k>=10) 
            {
                s[i]=k%10;add=k/10;flag=1;
            } 
            else 
            {
                s[i]=k;flag=0;add=0;
            }
        }
        if (flag) 
        {
            l=i+1;s[i]=add;
        } 
        else 
            l=i;
        for (i=0;i<l;i++)
            t[l-1-i]=s[i]+'0';
        t[l]='';
    }
    int main()
    {
        int i;
        cin>>a>>i;
        mult(a,i,t);
        cout<<t<<endl;
        return 0;
    }

    大数加法:

    #include <iostream>
    #include <string>
    using namespace std;
    char a[1000],b[1000],s[10000];
    void add(char a[],char b[],char s[])//a被加数,b加数,s和
    {
        int i,j,k,up,x,y,z,l;
        char *c;
        if (strlen(a)>strlen(b)) l=strlen(a)+2; else l=strlen(b)+2;
        c=(char *) malloc(l*sizeof(char));
        i=strlen(a)-1;
        j=strlen(b)-1;
        k=0;up=0;
        while(i>=0||j>=0)
        {
            if(i<0) x='0'; else x=a[i];
            if(j<0) y='0'; else y=b[j];
            z=x-'0'+y-'0';
            if(up) z+=1;
            if(z>9) {up=1;z%=10;} else up=0;
            c[k++]=z+'0';
            i--;j--;
        }
        if(up) c[k++]='1';
        i=0;
        c[k]='';
        for(k-=1;k>=0;k--)
            s[i++]=c[k];
        s[i]='';
    } 
    int main()
    {
        cin>>a>>b;
        add(a,b,s);
        cout<<s<<endl;
        return 0;
    }

    大数减法:

    #include <iostream>
    using namespace std;
    char a[1000],b[1000],s[10000];
    void sub(char a[],char b[],char s[])
    {
        int i,l2,l1,k;
        l2=strlen(b);l1=strlen(a);
        s[l1]='';l1--;
        for (i=l2-1;i>=0;i--,l1--)
            {
            if (a[l1]-b[i]>=0) 
                s[l1]=a[l1]-b[i]+'0';
            else
                {
                s[l1]=10+a[l1]-b[i]+'0';
                a[l1-1]=b[l1-1]-1;
                }
            }
        k=l1;
        while(a[k]<0) {a[k]+=10;a[k-1]-=1;k--;}
        while(l1>=0) {s[l1]=a[l1];l1--;}
    loop:
        if (s[0]=='0') 
            {
            l1=strlen(a);
            for (i=0;i<l1-1;i++) s[i]=s[i+1];
            s[l1-1]='';
            goto loop;
            }
        if (strlen(s)==0) {s[0]='0';s[1]='';}
    } 
    
    int main()
    {
        cin>>a>>b;
        sub(a,b,s);
        cout<<s<<endl;
        return 0;
    }

    大数阶乘:

    #include <iostream>
    #include <cmath>
    using namespace std;
    long a[10000];
    int factorial(int n)         //n为所求阶乘的n!的n
    {
        int i,j,c,m=0,w; 
        a[0]=1; 
        for(i=1;i<=n;i++)
       { 
            c=0; 
            for(j=0;j<=m;j++)
           { 
                a[j]=a[j]*i+c; 
                c=a[j]/10000; 
                a[j]=a[j]%10000; 
            } 
            if(c>0) {m++;a[m]=c;} 
        } 
        w=m*4+log10(a[m])+1;
        printf("%ld",a[m]); //        输出
        for(i=m-1;i>=0;i--) //
            printf("%4.4ld",a[i]);//
        printf("
    ");
        return w;            //返回值为阶乘的位数
    }
    
    //储存方法很巧,每一个a[i]中存四位,不足四位在前加0补齐

    大数求余:

    int mod(int B)     //A为大数,B为小数
    {
        int i = 0,r = 0;
        while( A[i] != '' )
        {
            r=(r*10+A[i++]-'0')%B;
        }
        return r ;    //r为余数
    }

    高精度任意进制转换:

    #include <iostream>
    #include <string>
    using namespace std;
    char s[1000],s2[1000];   // s[]:原进制数字,用字符串表示,s2[]:转换结果,用字符串表示
    long d1,d2;   // d1:原进制数,d2:需要转换到的进制数
    void conversion(char s[],char s2[],long d1,long d2)
    {
        long i,j,t,num;
        char c;
        num=0;
        for (i=0;s[i]!='';i++)
        {
            if (s[i]<='9'&&s[i]>='0') t=s[i]-'0'; else t=s[i]-'A'+10;
            num=num*d1+t;
        }
        i=0;
        while(1)
        {
            t=num%d2;
            if (t<=9) s2[i]=t+'0'; else s2[i]=t+'A'-10;
            num/=d2;
            if (num==0) break;
            i++;
        }
        for (j=0;j<=i/2;j++)
        {c=s2[j];s2[j]=s2[i-j];s2[i-j]=c;}
        s2[i+1]='';
    }
    int main()
    {
        while (1)
        {
            cin>>s>>d1>>d2;
            conversion(s,s2,d1,d2);
            cout<<s2<<endl;
        }
        return 0;
    }

    判断一个数是否素数:

    #include <iostream>//基本方法,n为所求数,返回1位素数,0为合数
    
    #include <cmath>
    
    using namespace std;
    
    int comp(int n){
    
    int i,flag=1;
    
        for (i=2;i<=sqrt(n);i++)
    
        if (n%i==0) {flag=0;break;}
    
        if (flag==1) return 1; else return 0;}

    素数表:

    int prime(int a[],int n)            //小于n的素数
    
    {   int i,j,k,x,num,*b;
    
        n++;
    
        n/=2;
    
        b=(int *)malloc(sizeof(int)*(n+1)*2);
    
        a[0]=2;a[1]=3;num=2;
    
        for(i=1;i<=2*n;i++)
    
            b[i]=0;
    
        for(i=3;i<=n;i+=3)
    
            for(j=0;j<2;j++)
    
                {
    
                x=2*(i+j)-1;
    
                while(b[x]==0)
    
                    {
    
                    a[num++]=x;
    
                    for(k=x;k<=2*n;k+=x)
    
                        b[k]=1;
    
                    }
    
                }
    
        return num; }                //小于n的素数的个数}
    
    bool flag[1000000];
    
    void prime(int M)               //01表
    
    {      int i , j;
    
           int sq = sqrt(double(M));      
    
           for(i = 0 ;i < M ;i ++)
    
                  flag[i] = true;     
    
           flag[1] = false;    flag[0] = false;
    
           for(i = 2 ;i <= sq ;i++)
    
                  if(flag[i])
    
                  {
    
                         for(j = i*i ;j < M ;j += i)
    
                                flag[j] = false;
    
                  }
    
    }

    Miller_Rabin随机素数测试算法:    

     说明:这种算法可以快速地测试一个数是否   满足素数的必要条件,但不是充分条件。不  过也可以用它来测试素数,出错概率很小,  对于任意奇数n>2和正整数s,该算法出错概率  至多为2^(-s),因此,增大s可以减小出错概  率,一般取s=50就足够了。
    #include<iostream>
    #include <cmath>
    using namespace std;
    int Witness(int a, int n)  
    {  
           int i, d = 1, x;  
           for (i = ceil( log( (float) n - 1 ) / log(2.0) ) - 1; i >= 0; i--)    
           {  
                  x = d;  
                  d = (d * d) % n;  
                  if ( (d == 1) && (x != 1) && (x != n-1) )
                         return 1;  
                  if ( ( (n - 1) & ( 1<<i ) ) >0 )
                         d = (d * a) % n;  
           }  
           return (d == 1 ? 0 : 1);          
    }   
    int Miller_Rabin(int n, int s)  
    {  
           int j, a;  
           for (j = 0; j < s; j++)  
           {    
                  a = rand() * (n - 2) / RAND_MAX + 1;  
                  if (Witness(a, n))
                         return 0;  
           }  
           return 1;        
    
    }  
    int main()
    {
    
           int x;
          cin>>x;
           cout<<Miller_Rabin(x , 50)<<endl;
           return 0;
    }
    
     

    KMP:

    #include<iostream>   
    #include<string>  
    using namespace std; 
    char  t[1010],p[100];  //t为大字符串,p为小字符串 
    int  next[100];
    void  sn()
    {
        int   j,k;   
        next[0]=-1;   
        j=1;   
        do
        {   
            k=next[j-1];   
            while(k!=-1 && p[k]!=p[j])   
                k=next[k];   
            next[j]=k+1;   
            j+=1;   
        }
        while(p[j]!='');   
    }   
    int   match(int x)      //x是大字符串下标,从头开始为0,j为小字符串下标
    {   
        int   k=x,j=0;   
        if(t[0]=='')
            return   0;   
        while(t[k]!='')
        {   
            while(j!=-1 && p[j]!=t[k])   
                j=next[j];   
            k+=1;
            j+=1;   
            if(p[j]=='')
                return   k-j;   //返回p所在的下标
        }   
        return -1;   //搜索失败返回-1
    }   
    int main()
    {
        int x=0;
        sn();
        int r=match( x );
        cout<<r<<endl;
    }

    (一)巴什博奕(Bash Game):

    只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。
         显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜。因此我们发现了如何取胜的法则:如果n=(m+1)r+s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜。
         这个游戏还可以有一种变相的玩法:两个人轮流报数,每次至少报一个,最多报十个,谁能报到100者胜。


    (二)威佐夫博奕(Wythoff Game):

    有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
         这种情况下是颇为复杂的。我们用(ak,bk)(ak ≤ bk ,k=0,1,2,...,n)表示两堆物品的数量并称其为局势,如果甲面对(0,0),那么甲已经输了,这种局势我们称为奇异局势。前几个奇异局势是:(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)。
         可以看出,a0=b0=0,ak是未在前面出现过的最小自然数,而 bk= ak + k,奇异局势有如下三条性质:
         1。任何自然数都包含在一个且仅有一个奇异局势中。
         由于ak是未在前面出现过的最小自然数,所以有ak > ak-1 ,而 bk= ak + k > ak-1 + k-1 = bk-1 > ak-1 。所以性质1。成立。
         2。任意操作都可将奇异局势变为非奇异局势。
         事实上,若只改变奇异局势(ak,bk)的某一个分量,那么另一个分量不可能在其他奇异局势中,所以必然是非奇异局势。如果使(ak,bk)的两个分量同时减少,则由于其差不变,且不可能是其他奇异局势的差,因此也是非奇异局势。
         3。采用适当的方法,可以将非奇异局势变为奇异局势。
         假设面对的局势是(a,b),若 b = a,则同时从两堆中取走 a 个物体,就变为了奇异局势(0,0);如果a = ak ,b > bk,那么,取走b   - bk个物体,即变为奇异局势;如果 a = ak ,   b < bk ,则同时从两堆中拿走 ak - ab - ak个物体,变为奇异局势( ab - ak , ab - ak+ b - ak);如果a > ak ,b= ak + k,则从第一堆中拿走多余的数量a - ak 即可;如果a < ak ,b= ak + k,分两种情况,第一种,a=aj (j < k),从第二堆里面拿走 b - bj 即可;第二种,a=bj (j < k),从第二堆里面拿走 b - aj 即可。
         从如上性质可知,两个人如果都采用正确操作,那么面对非奇异局势,先拿者必胜;反之,则后拿者取胜。
         那么任给一个局势(a,b),怎样判断它是不是奇异局势呢?我们有如下公式:
         ak =[k(1+√5)/2],bk= ak + k   (k=0,1,2,...,n 方括号表示取整函数)奇妙的是其中出现了黄金分割数(1+√5)/2 = 1。618...,因此,由ak,bk组成的矩形近似为黄金矩形,由于2/(1+√5)=(√5-1)/2,可以先求出j=[a(√5-1)/2],若a=[j(1+√5)/2],那么a = aj,bj = aj + j,若不等于,那么a = aj+1,bj+1 = aj+1+ j + 1,若都不是,那么就不是奇异局势。然后再按照上述法则进行,一定会遇到奇异
    局势。

    (三)尼姆博奕(Nimm Game):

    有三堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
         这种情况最有意思,它与二进制有密切关系,我们用(a,b,c)表示某种局势,首先(0,0,0)显然是奇异局势,无论谁面对奇异局势,都必然失败。第二种奇异局势是(0,n,n),只要与对手拿走一样多的物品,最后都将导致(0,0,0)。仔细分析一下,(1,2,3)也是奇异局势,无论对手如何拿,接下来都可以变为(0,n,n)的情形。
         计算机算法里面有一种叫做按位模2加,也叫做异或的运算,我们用符号(+)表示这种运算。这种运算和一般加法不同的一点是1+1=0。先看(1,2,3)的按位模2加的结果:
    1 =二进制01
    2 =二进制10
    3 =二进制11 (+)
    ———————
    0 =二进制00 (注意不进位)
         对于奇异局势(0,n,n)也一样,结果也是0。
         任何奇异局势(a,b,c)都有a(+)b(+)c =0。
    如果我们面对的是一个非奇异局势(a,b,c),要如何变为奇异局势呢?假设 a < b< c,我们只要将 c 变为 a(+)b,即可,因为有如下的运算结果: a(+)b(+)(a(+)b)=(a(+)a)(+)(b(+)b)=0(+)0=0。要将c 变为a(+)b,只要从 c中减去 c-(a(+)b)即可。
         例1。(14,21,39),14(+)21=27,39-27=12,所以从39中拿走12个物体即可达到奇异局势(14,21,27)。
         例2。(55,81,121),55(+)81=102,121-102=19,所以从121中拿走19个物品就形成了奇异局势(55,81,102)。
         例3。(29,45,58),29(+)45=48,58-48=10,从58中拿走10个,变为(29,45,48)。
         例4。我们来实际进行一盘比赛看看:
             甲:(7,8,9)->(1,8,9)奇异局势
             乙:(1,8,9)->(1,8,4)
             甲:(1,8,4)->(1,5,4)奇异局势
             乙:(1,5,4)->(1,4,4)
             甲:(1,4,4)->(0,4,4)奇异局势
             乙:(0,4,4)->(0,4,2)
             甲:(0.4,2)->(0,2,2)奇异局势
             乙:(0,2,2)->(0,2,1)
             甲:(0,2,1)->(0,1,1)奇异局势
             乙:(0,1,1)->(0,1,0)
             甲:(0,1,0)->(0,0,0)奇异局势
             甲胜。

     

     

    叉乘法求任意多边形面积

    语法:result=polygonarea(Point *polygon,int N);

    参数:

    *polygon:

    多变形顶点数组

    N:

    多边形顶点数目

    返回值:

    多边形面积

    注意:

     

     

    支持任意多边形,凹、凸皆可

     

    多边形顶点输入时按顺时针顺序排列

    源程序:

     

    typedef struct {
        double x,y;
    } Point;
    
    double polygonarea(Point *polygon,int N)
    {
        int i,j;
        double area = 0;
    
        for (i=0;i<N;i++) {
            j = (i + 1) % N;
            area += polygon[i].x * polygon[j].y;
            area -= polygon[i].y * polygon[j].x;
            }
    
        area /= 2;
        return(area < 0 ? -area : area);
    }
         

    求三角形面积

    语法:result=area3(float x1,float y1,float x2,float y2,float x3,float y3);

    参数:

    x1~3:

    三角形3个顶点x坐标

    y1~3:

    三角形3个顶点y坐标

    返回值:

    三角形面积

    注意:

     

     

    需要 math.h

    源程序:

     

     

    float area3(float x1,float y1,float x2,float y2,float x3,float y3)
    {
        float a,b,c,p,s;
        a=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
        b=sqrt((x1-x3)*(x1-x3)+(y1-y3)*(y1-y3));
        c=sqrt((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2));
        p=(a+b+c)/2;
        s=sqrt(p*(p-a)*(p-b)*(p-c));
        return s;
    }

    两点距离(2D、3D)

    语法:result=distance_2d(float x1,float x2,float y1,float y2);

    参数:

    x/y/z1~2:

    各点的x、y、z坐标

    返回值:

    两点之间的距离

    注意:

     

     

    需要 math.h

    源程序:

     

    float distance_2d(float x1,float x2,float y1,float y2) 
    {
        return(sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)));
    }
    float distance_3d(float x1,float x2,float y1,float y2,float z1,float z2)
    {return(sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2)));
    }
         

    射向法判断点是否在多边形内部

    语法:result=insidepolygon(Point *polygon,int N,Point p);

    参数:

    *polygon:

    多边形顶点数组

    N:

    多边形顶点个数

    p:

    被判断点

    返回值:

    0:点在多边形内部;1:点在多边形外部

    注意:

     

     

    若p点在多边形顶点或者边上,返回值不确定,需另行判断

     

    需要 math.h

    源程序:

     

    #define MIN(x,y) (x < y ? x : y)
    #define MAX(x,y) (x > y ? x : y)
    
    typedef struct {
        double x,y;
    } Point;
    
    int insidepolygon(Point *polygon,int N,Point p)
    {   int counter = 0;
        int i;
        double xinters;
        Point p1,p2;
    
        p1 = polygon[0];
        for (i=1;i<=N;i++) {
            p2 = polygon[i % N];
            if (p.y > MIN(p1.y,p2.y)) {
                if (p.y <= MAX(p1.y,p2.y)) {
                    if (p.x <= MAX(p1.x,p2.x)) {
                        if (p1.y != p2.y) {
                            xinters = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x;
                            if (p1.x == p2.x || p.x <= xinters)
                                counter++;}}}}
                p1 = p2;}
    
        if (counter % 2 == 0)
            return(OUTSIDE);
        else
            return(INSIDE);}

    判断点是否在线段上

    语法:result=Pointonline(Point p1,Point p2,Point p);

    参数:

    p1、p2:

    线段的两个端点

    p:

    被判断点

    返回值:

    0:点在不在线段上;1:点在线段上

    注意:

     

     

    若p线段端点上返回1

     

    需要 math.h

    源程序:

     

    #define MIN(x,y) (x < y ? x : y)
    #define MAX(x,y) (x > y ? x : y)
    
    typedef struct {
    double x,y;
    } Point;
    
    int FC(double x1,double x2)
    {
        if (x1-x2<0.000002&&x1-x2>-0.000002) return 1; else return 0;
    }
    
    
    int Pointonline(Point p1,Point p2,Point p)
    {
        double x1,y1,x2,y2;
        x1=p.x-p1.x;
        x2=p2.x-p1.x;
        y1=p.y-p1.y;
        y2=p2.y-p1.y;
        if (FC(x1*y2-x2*y1,0)==0) return 0;
        if ((MIN(p1.x,p2.x)<=p.x&&p.x<=MAX(p1.x,p2.x))&&
                (MIN(p1.y,p2.y)<=p.y&&p.y<=MAX(p1.y,p2.y)))
            return 1; else return 0;
    }
         

    判断两线段是否相交

    语法:result=sectintersect(Point p1,Point p2,Point p3,Point p4);

    参数:

    p1~4:

    两条线段的四个端点

    返回值:

    0:两线段不相交;1:两线段相交;2两线段首尾相接

    注意:

     

     

    p1!=p2;p3!=p4;

    源程序:

     

    #define MIN(x,y) (x < y ? x : y)
    #define MAX(x,y) (x > y ? x : y)
    
    typedef struct {
        double x,y;
    } Point;
    
    int lineintersect(Point p1,Point p2,Point p3,Point p4)
    {
        Point tp1,tp2,tp3;
        if ((p1.x==p3.x&&p1.y==p3.y)||(p1.x==p4.x&&p1.y==p4.y)||(p2.x==p3.x&&p2.y==p3.y)||(p2.x==p4.x&&p2.y==p4.y))
            return 2;
    //快速排斥试验
        if ((MIN(p1.x,p2.x)<p3.x&&p3.x<MAX(p1.x,p2.x)&&MIN(p1.y,p2.y)<p3.y<MAX(p1.y,p2.y))||
                (MIN(p1.x,p2.x)<p4.x&&p3.x<MAX(p1.x,p2.x)&&MIN(p1.y,p2.y)<p3.y<MAX(p1.y,p2.y)))
            ;else return 0;
    
    //跨立试验
        tp1.x=p1.x-p3.x;
        tp1.y=p1.y-p3.y;
        tp2.x=p4.x-p3.x;
        tp2.y=p4.y-p3.y;
        tp3.x=p2.x-p3.x;
        tp3.y=p2.y-p3.y;
        if ((tp1.x*tp2.y-tp1.y*tp2.x)*(tp2.x*tp3.y-tp2.y*tp3.x)>=0) return 1; else return 0;}
         

    点到线段最短距离

    语法:result=mindistance(Point p1,Point p2,Point q);

    参数:

    p1、p2:

    线段的两个端点

    q:

    判断点

    返回值:

    点q到线段p1p2的距离

    注意:

     

     

    需要 math.h

    源程序:

     

    #define MIN(x,y) (x < y ? x : y)
    #define MAX(x,y) (x > y ? x : y)
    
    typedef struct {
        double x,y;
    } Point;
    
    double mindistance(Point p1,Point p2,Point q)
    {
        int flag=1;
        double k;
        Point s;
        if (p1.x==p2.x) {s.x=p1.x;s.y=q.y;flag=0;}
        if (p1.y==p2.y) {s.x=q.x;s.y=p1.y;flag=0;}
        if (flag)
            {
            k=(p2.y-p1.y)/(p2.x-p1.x);
            s.x=(k*k*p1.x+k*(q.y-p1.y)+q.x)/(k*k+1);
            s.y=k*(s.x-p1.x)+p1.y;
            }
        if (MIN(p1.x,p2.x)<=s.x&&s.x<=MAX(p1.x,p2.x))
            return sqrt((q.x-s.x)*(q.x-s.x)+(q.y-s.y)*(q.y-s.y));
        else
            return MIN(sqrt((q.x-p1.x)*(q.x-p1.x)+(q.y-p1.y)*(q.y-p1.y)),sqrt((q.x-p2.x)*(q.x-p2.x)+(q.y-p2.y)*(q.y-p2.y)));
    }

    求两直线的交点

    语法:result=mindistance(Point p1,Point p2,Point q);

    参数:

    p1~p4:

    直线上不相同的两点

    *p:

    通过指针返回结果

    返回值:

    1:两直线相交;2:两直线平行

    注意:

     

     

    如需要判断两线段交点,检验k和对应k1(注释中)的值是否在0~1之间,用在0~1之间的那个求交点

    源程序:

     

    typedef struct {
       double x,y;
    } Point;
    
    int linecorss(Point p1,Point p2,Point p3,Point p4,Point *p)
    {
       double k;
    
       //同一直线
    
      if ((p4.x-p3.x)*(p1.y-p3.y)-(p4.y-p3.y)*(p1.x-p3.x)==0&&
    
            (p2.x-p1.x)*(p1.y-p3.y)-(p2.y-p1.y)*(p1.x-p3.x)==0) return 2;
    
       //平行,不同一直线
    
      if ((p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y)==0) return 0;
    
        k=((p4.x-p3.x)*(p1.y-p3.y)-(p4.y-p3.y)*(p1.x-p3.x))/((p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y));
    
    //k1=((p2.x-p1.x)*(p1.y-p3.y)-(p2.y-p1.y)*(p1.x-p3.x))/((p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y));
    
       (*p).x=p1.x+k*(p2.x-p1.x);
    
       (*p).y=p1.y+k*(p2.y-p1.y);
    
       return 1;//有交点}
         

    整数拆分不可重复:

    #include <iostream>
    #include <memory>
    using namespace std;
    const int MAX = 500;
    long long data[MAX][MAX];
    int main()
    {
        int i,j;
        memset(data, 0, sizeof(int)*MAX);
        for(i = 0; i < MAX; i++)
            data[0][i] = 0;
        for(i = 0; i < MAX; i++)
        {
            for(j = 0; j < MAX; j++)
            {
                int sum = j*(j+1)/2;
                if(i > sum) data[i][j] = 0;
                else if(i == sum) data[i][j] = 1;
                else
                {
                    if(i == j) data[i][j] = 1 + data[i][j-1];
                    else if(i < j) data[i][j] = data[i][i];
                    else data[i][j] = data[i-j][j-1] + data[i][j-1];
                }
            }
        }
        int n;
        while(cin >> n)
            cout << data[n][n] << endl;
        return 0;
    }

    整数拆分积最大:

    nt data[100];
    void main(int n;)
    {    int k = 2;
        for(; n >= k; n-=k,k++)
            data[k] = k;
        for(int i = k-1; i >= 2 && n; i--, n--)
            data[i]++;
        data[k-1] += n;
        for(int j = 2; j < k; j++)
            cout << data[j] << " ";
        cout << endl; }

    整数的无序拆分(可重复):

    #include <iostream>       //求出可分解个数
    #include <memory>
    using namespace std;
    const int MAX = 600;
    long long data[MAX][MAX];
    int main()
    {
        int i,j;
        memset(data, 0, sizeof(int)*MAX);
        for(j = 0; j < MAX; j++)
            data[0][j] = 0;    
        for(i = 1; i < MAX; i++)
        {
            for(j = 1; j < MAX; j++)
            {
                if(i == j) 
                    data[i][j] = data[i][j-1]+1;
                else if(i < j) 
                    data[i][j] = data[i][i];
                else 
                    data[i][j] = data[i][j-1]+data[i-j][j];
            }
        }    
        int n;
        while(cin >> n)
            cout << data[n][n] << endl;
        return 0;
    }

    整数的无序拆分(可重复):

    #include <iostream>   //列出分解情况
    #include <memory>
    using namespace std;
    const int MAX = 300;
    int data[MAX];
    int main()
    {
        int i,n;
        cin >> n;
        for(i = 0; i < n; i++)
        {
            data[i] = 1;
            printf("1");
        }
        printf("
    ");    
        int size = n;
        while(size > 1)
        {
            int t, p, r;
            t = data[size-1] + data[size-2];
            p = t / (data[size-2]+1);
            r = t % (data[size-2]+1);
            
            t = data[size-2]+1;
            i = size - 2;
            size = size - 2 + p;
            for(; i < size; i++)
                data[i] = t;
            data[size-1] += r;
            
            for(i = 0; i < size; i++)
                printf("%d", data[i]);
            printf("
    ");
        }
        return 0;
    }

    约瑟夫环:

    void f()
    {
        int n , k , m , i , j , start;
        while(cin>>n>>k>>m )   //n代表有多少个人 , k表示叫到k的人出列 , m 表示第一次谁先开始叫
        {
            start = 0;
            if( !n && !k && !m)
                return 0;
            for(i = 1 ;i < n; i++)
            {
                start = (start + k) % i;
            }
            start++;
            start = (start + m) % n;
            if(!start)
                cout<<n<<endl;
            else
                cout<<start<<endl;
        }
        return ;
    }
    #include <stdio.h>
    main()
    {
       int n, m, i, s=0;
       printf ("N M = "); scanf("%d%d", &n, &m);
       for (i=2; i<=n; i++) s=(s+m)%i;
       printf ("The winner is %d
    ", s+1);
    }
    

    二分法:

    #include<iostream>
    #include<Cmath>
    #define limit 1e-6
    using namespace std;
    double x, y , c,p , a , b ;
    double f(double l)
    {
        return c*sqrt(x*x-l*l)+c*sqrt(y*y-l*l)-sqrt(x*x-l*l)*sqrt(y*y-l*l);
    }
    int main()
    {
        double mid;
        while(cin>>x>>y>>c)
        {
            a = 0;
            if(x > y)
                swap(x,y);
            b = x;                //f(a) <= 0 , f(b) >= 0
            mid = (a + b ) * 0.5000;
            while(1)
            {
                if(fabs(f(mid)) < limit)
                {
                    printf("%.3f
    ",mid);
                    break;
                }
                if(f(mid)*f(a) <= 0)
                {
                    b = mid;
                    mid = 0.5000*(a + mid);
                }
                if(f(mid)*f(b) <= 0)
                {
                    a = mid;
                    mid = 0.5000*(mid + b);
                } 
            }
        }
        return 0;
    }
     

     

  • 相关阅读:
    手机号 验证(正则)
    静态库相关
    添加友盟SDK,实现新浪分享和微信朋友圈分享的关键代码
    删除Mac 系统中多出得MobileBackups 文件夹
    浏览器判断检测手机中是否安装了ios/android客户端程序
    浏览器判断是否安装了ios/android客户端程序
    自定义TextField的删除按钮
    应用崩溃日志解析
    关于UITextView的一些问题
    关于UIColor这个类的一些不知道的事
  • 原文地址:https://www.cnblogs.com/pyyyyyy/p/10811111.html
Copyright © 2020-2023  润新知