高斯消元 初见

今天,跟着HYM大神学习了高斯消元,思想很简单,不过用处很大,也有一些细节。

其实就是消元的思想,对n个方程不断消元,在解出一个未知数之后,回带求出其他未知数。如果回带时,我们发现方程左面为0,右面不为0,则无解;若左面为0,右面为0,则多解。

 

cogs1845||bzoj1013 球星空间生成器sphere

题目大意:给出n维空间内一个球上的n+1个点,求圆心坐标。

思路:比较裸的高斯消元,唯一就是自己建方程。设圆心坐标(a,b,c,d,...),我们发现,球上各点到圆心距离相等,于是就有连等式:(a-a1)^2+(b-b1)^2+(c-c1)^2+(d-d1)^2+...=(a-a2)^2+(b-b2)^2+(c-c2)^2+(d-d2)^2...=...=(a-an)^2+(b-bn)^2+(c-cn)^2+(d-dn)^2;选取等号左右的式子建方程,得到n个方程,求解就可以了。由题意可知,这里不需要考虑无解的情况。

#include<iostream>

#include<cstdio>

#include<algorithm>

#include<cmath>

using namespace std;

double a[100][100]={0},b[100]={0},c[100][100];

int main()

{

    freopen("bzoj_1013.in","r",stdin);

    freopen("bzoj_1013.out","w",stdout);

    

    int n,i,j,k,maxn,maxi;

    double t;

    scanf("%d",&n);

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

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

      {

           scanf("%lf",&c[i][j]);

           c[i][j]*=1.0;

      }

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

    {

      t=0;

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

      {

           a[i][j]=2*(c[i][j]-c[i+1][j]);

           t+=c[i][j]*c[i][j]-c[i+1][j]*c[i+1][j];

      }

      a[i][n+1]=t;

    }

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

    {

        if (a[i][i]==0)

        {

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

              if (a[j][i]!=0)

              {

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

                      swap(a[i][k],a[j][k]);

                    break;

              }

        }

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

        {

            t=a[j][i]/a[i][i];

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

              a[j][k]-=a[i][k]*t;

        }

    }

    for (i=n;i>=1;--i)

    {

        b[i]=a[i][n+1]/a[i][i];

        for (j=i-1;j>=1;--j)

        {

            a[j][n+1]-=a[j][i]*b[i];

            a[j][i]=0;

        }

    }

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

      printf("%0.3f ",b[i]);

    printf("%0.3f\n",b[n]);

    

    fclose(stdin);

    fclose(stdout);

}
View Code

 

bzoj1923外星千足虫

题目大意:给定m个方程,有n个未知数,判断有无唯一解,若有求出最早在第几个方程处判断出的,并输出答案;无解就输出“Cannot Determine”。

思路:因为要求最早在哪求出解,所以一开始想二分一下,回来觉得会超时,就。。。了一下学长的博客,其实只需要在对第i个合法方程(第i个未知数前系数不为0)操作的时候,取max就可以了(这种思想要掌握)。这道题目中,只有0、1,所以可以用xor来计算。一开始狂wa,回来才发现,回带的时候,要判断几个不为0,否则xor后就呵呵了。

#include<iostream>

#include<cstdio>

#include<algorithm>

using namespace std;

struct use{

    int num[1002],p;

}a[2001],b;

int n,m,ans=0,k;

void gauss()

{

    int i,j,k;

    bool f=false;

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

    {

        if (a[i].num[i]==0) 

        {

          f=false;

          for (j=i+1;j<=m;++j)

            if (a[j].num[i]!=0)

            {

                swap(a[i],a[j]);

                f=true;break;

            }

          if (!f)

          {

              ans=0;return;

          }

        }

        ans=max(ans,a[i].p);

        for (j=i+1;j<=m;++j)

        {

          if (a[j].num[i]!=0)

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

                a[j].num[k]^=a[i].num[k]; 

        }

    }

    for (i=n;i>=1;--i)

    {

        b.num[i]=a[i].num[n+1]/a[i].num[i];

        if (b.num[i])

        {

          for (j=i-1;j>=1;--j)

          {

            if (a[j].num[i])

            {

              a[j].num[n+1]=a[j].num[n+1]^b.num[i];

              a[j].num[i]=0;

            }

          }

        }

    }

}

int main()

{

    int i,j;

    char ch;

    scanf("%d%d",&n,&m);

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

    {

        scanf("%*c");

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

        {

            scanf("%c",&ch);

            a[i].num[j]=ch-'0';

        }

        scanf("%d",&a[i].num[n+1]);

        a[i].p=i;

    }

    gauss();

    if (ans==0) printf("Cannot Determine\n");

    else

    {

        printf("%d\n",ans);

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

        {

            if (b.num[i]==0) printf("Earth\n");

            else printf("?y7M#\n");

        }

    }

}
View Code

 

你可能感兴趣的:(高斯消元 初见)