106632.生成子群阶数···············不会!!!!!!!!!!

 

#include <bits/stdc++.h>

using namespace std;

#define SIZE 1000

int group[SIZE][SIZE]={0};

int n=0;

int e=0;

int scy=0;

int mg[SIZE][SIZE]={0};//非循环群包含每个元素的最小的群

void input()

{

    /*

        输入群中的元素以及运算结果

        首先输入阶数n

        最后输入n*n个元素,表示运算的结果

    */

    printf("输入元素的阶数n(n<=250):");

    scanf("%d",&n);

    printf("在这里我们分别将n个元素表示为:1,2,3,4,...,n,我们假设群的运算为*,");

    printf("\n那么请你依次输入\n1*1,1*2,...,1*n,\n2*1,2*2...,2*n,\n...\nn*1,n*2,...,n*n\n的结果.\n");

    for(int i=1;i<=n;i++)

    {

        for(int j=1;j<=n;j++)

        {

            scanf("%d",&group[i][j]);

        }

    }

}

int prime(int n)

{

    //判断n是否是质数

    for(int i=2;i<=sqrt(n);i++)

    {

        if(n%i==0)return 0;

    }

    return 1;

}

void find_e()

{

    for(int i=1;i<=n;i++)

    {

        for(int j=1;j<=n+1;j++)

        {

            if(j==n+1)

            {

                e=i;

                return;

            }

            ///

            //printf("%d\n",group[i][j]);

            if(group[i][j]!=j||group[j][i]!=j)

            {

                break;

            }

        }

    }

}

int same_with_klein()

{

    //首先筛选出所有阶为2的元素

    int grade_is_2[SIZE]={0},cnt=0;

    for(int i=1;i<=n;i++)

    {

        if(group[i][i]==e&&i!=e)grade_is_2[++cnt]=i;

    }

    //构造克莱因群的同构;

    if(cnt<3)return 0;

    for(int i=1;i<=cnt;i++)

    {

        for(int j=i+1;j<=cnt&&j!=i;j++)

        {

            for(int k=j+1;k<=cnt&&k!=j&&k!=i;k++)

            {

                if(group[grade_is_2[i]][grade_is_2[j]]==grade_is_2[k]&&group[grade_is_2[j]][grade_is_2[i]]==grade_is_2[k]&&

                    group[grade_is_2[i]][grade_is_2[k]]==grade_is_2[j]&&group[grade_is_2[k]][grade_is_2[i]]==grade_is_2[j]&&

                    group[grade_is_2[j]][grade_is_2[k]]==grade_is_2[i]&&group[grade_is_2[k]][grade_is_2[j]]==grade_is_2[i])

                    return 1;

            }

        }

    }

    return 0;

}

int is_scy(int x)

{

    int exist[256]={0};

    int t=x;

    for(int i=1;i<=n;i++)

    {

        exist[group[t][x]]=1;

        t=group[t][x];

    }

    for(int i=1;i<=n;i++)

    {

        if(exist[i]==0)return 0;

    }

    return 1;

}

int cycle_or_no()

{

    if(prime(n)==1)return 1;

    if(same_with_klein()==1)return 0;//判断是否有和克莱因群同构的子群

    //穷举寻找生成元

    for(int i=1;i<=n;i++)

    {

        if(is_scy(i)==1)

        {

            scy=i;

            return 1;

        }

    }

    return 0;

}

int in(int t,int mem[])

{

    //判断t在不在mem数组中

    for(int i=1;mem[i]!=0;i++)

    {

        if(t==mem[i])return 1;

    }

    return 0;

}

void find_d_sub_group(int d,int num)

{

    //求n/d阶生成元产生的子群

    /*

    定理10.14 设G=<a>是循环群.

    (1) G的子群仍是循环群.

    (3) 若G=<a>是n阶循环群,则对n的每个正因子d,

    eG恰好含有一个d 阶子群.那么生成元的阶数是n/d.

    */

    //根据以上定理求所有子群

    int mem[SIZE]={0};

    int t;

    int i,cnt=0;

    //printf("e=%d\n",e);

    for(i=1;i<=n;i++)

    {

        //寻找n/d阶生成元

        if(i!=e)t=i;

        else continue;

        int j=0;

        for(j=1;j<n/d;j++)

        {

            t=group[t][i];

            if(j<n/d-1&&t==e)break;

        }

        if(t==e&&j==n/d)break;//这个地方不对

    }

    //此时i就是那个生成元

    if(i>n)return ;

    t=i;

    mem[++cnt]=e;

    while(in(t,mem)!=1)

    {

        mem[++cnt]=t;

        t=group[t][i];

    }

    printf("子群中的元素有:{");

    for(int i=1;i<=cnt;i++)

    {

        printf("%d",mem[i]);

        if(i!=cnt)printf(",");

    }

    printf("}\n");

}

void cycle_sub_group()

{

    //找出所有的d阶子群

    //如果群是循环群

    /*

    定理10.14 设G=<a>是循环群.

    (1) G的子群仍是循环群.

    (3) 若G=<a>是n阶循环群,则对n的每个正因子d,

    eG恰好含有一个d 阶子群.那么生成元的阶数是n/d.

    */

    //根据以上定理求所有子群

    int cnt=0;

    for(int i=1;i<=n;i++)

    {

        if(n%i==0)

            find_d_sub_group(i,++cnt);

    }

    //输出一个只有单位元的子群

    printf("子群中的元素有:{%d}\n",e);

}

void find_min_group(int i)

{

    int cnt=0;

    int t=i;

    mg[i][++cnt]=e;

    if(i==e)return;//如果这个元素是单位元则里面只有单位元直接返回

    mg[i][++cnt]=i;

    //一开始集合里只有这个元素本身和单位元

    //接从前到后遍历这个集合

    //每次把当前元素和它前面的所有元素(包含它自己)乘一遍,

    //如果出现了新元素就添加到集合的后面

    //遍历完就得到了一个最小的子群

    int now=1;

    for(;now<=cnt;now++)

    {

        for(int k=1;k<=now;k++)

        {

//            printf("此时包含%d的最小的群中的元素有:",i);

//            for(int ii=1;mg[i][ii]!=0;ii++)printf("%d,",mg[i][ii]);

//            printf("\n");

            if(in(group[mg[i][now]][mg[i][k]],mg[i])!=1)

            {

                mg[i][++cnt]=group[mg[i][now]][mg[i][k]];

            }

            if(in(group[mg[i][k]][mg[i][now]],mg[i])!=1)

            {

                mg[i][++cnt]=group[mg[i][k]][mg[i][now]];

            }

        }

    }

    sort(mg[i]+1,mg[i]+cnt+1);

}

void find_every_min_group()

{

    //寻找包含每个元素的最小的群

    for(int i=1;i<=n;i++)

    {

        find_min_group(i);

    }

}

int g_equal(int a,int b)

{

    //判断两个群是否相等

//    printf("判断第%d和第%d个群是否相等\n",a,b);

//    for(int i=1;mg[a][i]!=0;i++)printf("%d,",mg[a][i]);

//    printf("这些是第%d个群中的元素\n",a);

//    for(int i=1;mg[b][i]!=0;i++)printf("%d,",mg[b][i]);

//    printf("这些是第%d个群中的元素\n",b);

    for(int i=1;;i++)

    {

        if(mg[a][i]==0&&mg[b][i]==0)return 1;

        else

        {

            if(mg[a][i]!=mg[b][i])return 0;

        }

    }

}

void col(int a,int b,int num)

{

    //将mg[a]和mg[b]两个群合并到mg[num]中

    //首先把a、b中的所有元素提取出来

    int ab[SIZE]={0};

    int i=0;

//    printf("第%d个子群的元素有:",a);

//    for(int ii=1;mg[a][ii]!=0;ii++)printf("%d ",mg[a][ii]);

//    printf("\n");

//    printf("第%d个子群的元素有:",b);

//    for(int ii=1;mg[b][ii]!=0;ii++)printf("%d ",mg[b][ii]);

//    printf("\n");

    for(i=1;mg[a][i]!=0;i++)

    {

        ab[i]=mg[a][i];

    }

    int j=1;

    while(mg[b][j]!=0)

    {

        if(in(mg[b][j],ab)!=1)ab[i++]=mg[b][j];

        j++;

    }

    sort(ab+1,ab+i);

    for(int ii=1;ab[ii]!=0;ii++)

    {

        mg[num][ii]=ab[ii];

    }

    //下面这一段是把所有元素进行运算然后求出子群

    i--;

    int now=1;

    for(;now<=i;now++)

    {

        for(int k=1;k<=now;k++)

        {

//            printf("此时第%d个群中的元素有:",num);

//            for(int ii=1;mg[num][ii]!=0;ii++)printf("%d,",mg[num][ii]);

//            printf("\n");

            if(i>=n)

            {

                sort(mg[num]+1,mg[num]+i+1);

                return;

            }

            if(in(group[mg[num][now]][mg[num][k]],mg[num])!=1)

            {

                mg[num][++i]=group[mg[num][now]][mg[num][k]];

            }

            if(in(group[mg[num][k]][mg[num][now]],mg[num])!=1)

            {

                mg[num][++i]=group[mg[num][k]][mg[num][now]];

            }

        }

    }

    sort(mg[num]+1,mg[num]+i+1);

//    printf("此时第%d个群中的元素有:",num);

//    for(int ii=1;mg[num][ii]!=0;ii++)printf("%d,",mg[num][ii]);

//    printf("\n");

}

void print_sub_group_of_no_cycle(int x,int cnt)

{

    printf("第%d个子群中的元素有{",cnt);

    for(int i=1;mg[x][i]!=0;i++)

    {

        printf("%d",mg[x][i]);

        if(mg[x][i+1]!=0)

            printf(",");

    }

    printf("}\n");

}

void no_cycle_sub_group()

{

    //非循环群的子群

    //先找包含每个元素的最小的群

    find_every_min_group();

    //对最小群去重

    for(int i=1;i<=n;i++)

    {

        for(int j=i+1;j<=n;j++)

        {

            if(i==j)continue;

            int xiangdeng=g_equal(i,j);

//            if(xiangdeng)printf("第%d个和第%d个群相等\n",i,j);

//            else printf("第%d个和第%d个群不相等\n",i,j);

            if(xiangdeng==1)

            {

                for(int k=1;mg[j][k]!=0;k++)

                {

                    mg[j][k]=0;

                }

            }

        }

    }

    //每次再选择两个群合并,

    //新群如果没出现过就添加到群的集合

    //最后就能得到所有子群

    int sum=n;//合并群的总数

    int same=0;

    for(int i=1;i<=sum;i++)

    {

        for(int j=i+1;j<=sum;j++)

        {

            if(i!=j)

            {

                col(i,j,sum+1);

                same=0;

                for(int k=1;k<=sum;k++)

                {

                    if(g_equal(k,sum+1)==1)//去重

                    {

                        same=1;

                        for(int ii=1;mg[sum+1][ii]!=0;ii++)

                        {

                            mg[sum+1][ii]=0;

                        }

                        break;

                    }

                }

                if(same==0)sum++;

            }

        }

    }

    //输出所有子群

    int cnt=0;

    for(int i=1;i<=sum;i++)

    {

        if(mg[i][1]==0)continue;

        else print_sub_group_of_no_cycle(i,++cnt);

    }

}

int main()

{

    input();

    find_e();//找到群的单位元

    int cycle=cycle_or_no();

    printf("该群的单位元为:%d\n",e);

    if(cycle==1)

    {

        //如果群是循环群

        /*

            定理10.14 设G=<a>是循环群.

            (1) G的子群仍是循环群.

            (3) 若G=<a>是n阶循环群,则对n的每个正因子d,G恰好含有一个d 阶子群.那么生成元的阶数是n/d.

        */

        //根据以上定理求所有子群

        cycle_sub_group();

    }

    else//如果是非循环群

    {

        no_cycle_sub_group();

    }

    return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值