高斯消元总结

摘要:
实现step1:交换step2:将每行第一系数化为1step3:消成倒三角step4:回代求解ilvoidGauss(){fp//枚举列{reintnow=i;fp//枚举行ifnow=j;ifswap;fpfqa[j][k]-=a[i][k]*a[j][i]/a[i][i];}fq{ans[i]=a[i][n+1];fqans[i]-=ans[j]*a[i][j];ans[i]/=a[i][i];}}最关键的就是了。实现解这种方程不难,和解加减方程差不多,原理是不断消去倒三角左边的系数。一开始消下面的系数,往回代时消上面的。除了continue,代码思路一致。例题T1Luogu3389高斯消元法见上T2hihoCoder1196高斯消元法二据说异或方程组高斯消元和普通高斯消元一模一样,就是把减改成异或。显然高斯消元解异或方程组。

https://zybuluo.com/ysner/note/1106886

本质

模拟加减消元,先消成上三角再代入求解。
据说是小学内容???

列方程

有这个量的影响就赋系数。

实现(加减方程组)

  • step 1:交换(将当前列系数绝对值最大的放到当前行
  • step 2:将每行第一系数化为1
  • step 3:消成倒三角(在下面的方程中减去上面的方程)
  • step 4:回代求解
il void Gauss()
{
  fp(i,1,n)//枚举列
    {
      re int now=i;
      fp(j,i+1,n)//枚举行
    if(fabs(a[j][i])+eps>fabs(a[now][i])) now=j;
      if(now^i) swap(a[i],a[now]);
      fp(j,i+1,n)
    fq(k,n+1,i)
    a[j][k]-=a[i][k]*a[j][i]/a[i][i];
    }
  fq(i,n,1)
    {
      ans[i]=a[i][n+1];
      fq(j,n,i+1) ans[i]-=ans[j]*a[i][j];
      ans[i]/=a[i][i];
    }
}

最关键的就是(a[j][k]-=a[i][k]*a[j][i]/a[i][i])了。
此时上面所有方程第一系数在(/a[i][i])后已经被视为(1)
想想平时怎么解方程的。
先把上面方程乘上当前方程第一系数(即(*a[j][i])),再同位项相减即可。

实现(异或方程组)

解这种方程不难,和解加减方程差不多,原理是不断消去倒三角左边的系数。一开始消下面的系数,往回代时消上面的。
除了continue,代码思路一致。

il void Gauss()
{
  fp(i,1,n)
    {
      re int now=i;
      fp(j,i+1,n) if(a[j][i]>a[now][i]) now=j;
      if(now^i) swap(a[now],a[i]);
      if(!a[i][i]) continue;
      fp(j,i+1,n) if(a[j][i]) a[j]^=a[i];
    }
  fq(i,n,1)
    fq(j,i-1,1)
    if(a[j][i]) a[j]^=a[i];
}

特殊情况

  • 无解:第一系数为0,常数非0
  • 无数解:第一系数为0,常数为0
    在开头交换后判一下系数最大值是否为0,有一个就记(flag=1),回代时方程形式为(x=b),判b是否为0即可。
    (注意先判无解,判完后若(flag=1),就是无穷解)

例题

T1 Luogu3389【模板】高斯消元法

见上

T2 hihoCoder1196 高斯消元法二

据说异或方程组高斯消元和普通高斯消元一模一样,就是把减改成异或。
若只有01建议用bitset压常数

bitset<50>a[50];
il void Gauss()
{
  fp(i,1,30)
    {
      re int now=i;
      fp(j,i+1,30)
	if(a[j][i]>a[now][i]) now=j;
      if(now^i) swap(a[now],a[i]);
      fp(j,i+1,30) if(a[j][i]) a[j]^=a[i];
    }
  fq(i,30,1)
    fq(j,i-1,1)
    if(a[j][i]) a[j]^=a[i];
}
int main()
{
  fp(i,1,5) scanf("%s",s[i]+1);
  fp(i,1,5)
    fp(j,1,6)
    {
      re int p=pos(i,j),l=pos(i,j-1),r=pos(i,j+1),u=pos(i-1,j),d=pos(i+1,j);
      a[p][p]=1;a[p][31]=(s[i][j]-'0')^1;
      if(i>1) a[p][u]=1;if(i<5) a[p][d]=1;if(j>1) a[p][l]=1;if(j<6) a[p][r]=1;
    }
  Gauss();
  return 0;
}

T3Luogu2962 [USACO09NOV]灯Lights

给定一个无向联通图,开始点值全为0。你可以选择将一个点和与其相邻的点同时取反,问最少进行多少次这样的操作可以使点值全为1。

显然高斯消元解异或方程组。
而且由于方程内值只有(0/1),可以开(bitset)使复杂度降到(O(frac{n^3}{64}))
注意到这种方程解起来很容易得到形如(0x=0)的表达式(由于保证有解,不考虑(0x=b))。此时我们要枚举这个(x),才能继续往回代。

bitset<50>a[50];
int n,m,ans=1e9,tag[50];
il void Gauss()
{
  fp(i,1,n)
    {
      re int now=i;
      fp(j,i+1,n) if(a[j][i]>a[now][i]) now=j;
      if(now^i) swap(a[now],a[i]);
      if(!a[i][i]) continue;
      fp(j,i+1,n) if(a[j][i]) a[j]^=a[i];
    }
}
il void dfs(re int x,re int tot)
{
  if(tot>=ans) return;
  if(!x) {ans=tot;return;}
  if(a[x][x])
    {
      re int t=a[x][n+1];
      fp(i,x+1,n) if(a[x][i]) t^=tag[i];
      tag[x]=t;
      dfs(x-1,tot+t);
    }
  else
    {
      tag[x]=0;dfs(x-1,tot);
      tag[x]=1;dfs(x-1,tot+1);
    }
}
int main()
{
  n=gi();m=gi();
  fp(i,1,m)
    {
      re int u=gi(),v=gi();
      a[u][v]=a[v][u]=1;
    }
  fp(i,1,n) a[i][i]=a[i][n+1]=1;
  Gauss();
  dfs(n,0);
  printf("%d
",ans);
  return 0;
}

T4Luogu2447 [SDOI2010]外星千足虫

给m个方程,最多n个未知数,解出方程并询问这最少需要要前几个方程组。

太板子了。
注意至少要(n)个方程。

il int Gauss(re int m)
{
  fp(i,1,m) fp(j,1,n) a[i]=aa[i];
  fp(i,1,n)
    {
      re int now=i;
      fp(j,i+1,m) if(a[j][i]>a[now][i]) now=j;
      if(now^i) swap(a[now],a[i]);
      if(a[i][i]==0) return 0;
      fp(j,i+1,m) if(a[j][i]) a[j]^=a[i];
    }
  fq(i,m,1)
    fq(j,i-1,1)
    if(a[j][i]) a[j]^=a[i];
  if(mm==m) fp(i,1,n) ans[i]=a[i][n+1];
  return 1;
}
int main()
{
  n=gi();mm=m=gi();
  fp(i,1,m)
    {
      scanf("%s",s+1);re int len=strlen(s+1);
      fp(j,1,len)
      if(s[j]=='1') a[i][j]=aa[i][j]=1;
      a[i][n+1]=aa[i][n+1]=gi();
    }
  if(!Gauss(m)) {puts("Cannot Determine");return 0;}
  re int l=n,r=m;
  while(l<r)
    {
      re int mid=l+r>>1;
      if(Gauss(mid)) r=mid;
      else l=mid+1;
    }
  printf("%d
",l);
  fp(i,1,n)
    if(ans[i]&1) puts("?y7M#");
    else puts("Earth");
  return 0;
}

T5Luogu2973 [USACO10HOL]赶小猪

一个无向图,节点1有一个炸弹,在每个单位时间内,有p/q的概率在这个节点炸掉,有1-p/q的概率随机选择一条出去的路到其他的节点上。问最终炸弹在每个节点上爆炸的概率。

看到题就想起了[HNOI2013]游走
好像思路方程都是一样的咦。
不过高斯消元解的应该是炸弹到某点的概率,炸弹爆炸概率最后再乘。

il void Gauss()
{
  fp(i,1,n)//枚举列数
    {
      re int now=i;
      fp(j,i+1,n)//枚举行
    if(fabs(a[j][i])+eps>fabs(a[now][i])) now=j;
      if(now^i) swap(a[i],a[now]);
      fp(j,i+1,n)
    fq(k,n+1,i)
    a[j][k]-=a[i][k]*a[j][i]/a[i][i];
    }
  fq(i,n,1)
    {
      ans[i]=a[i][n+1];
      fq(j,n,i+1) ans[i]-=ans[j]*a[i][j];
      ans[i]/=a[i][i];
    }
}
int main()
{
  memset(h,-1,sizeof(h));
  n=gi();m=gi();p=gi();q=gi();pi=(double)1.0*p/q;
  fp(i,1,m)
    {
      re int u=gi(),v=gi();
      add(u,v);
    }
  a[1][n+1]=1;
  fp(u,1,n)
    {
      a[u][u]=1;
      for(re int i=h[u];i+1;i=e[i].next)
    {
      re int v=e[i].to;
      a[u][v]=-1.0*(1-pi)/in[v];
    }
    }
  Gauss();
  fp(i,1,n) printf("%.9lf
",ans[i]*pi);
  return 0;
}

T6 bzoj3270博物馆

给定一个无向联通图,两个人分别在(a),(b)两点。在每一轮决策中,他们有(pi)的概率选择不动,有(1-pi)的概率等概率到任意一相邻房间。问在每个房间相遇的概率。
这题挺新奇的是吧。。。
要求每个房间的概率,我们就要求出每个状态的概率(即(a)在哪个点,(b)在哪个点)。
所以我们把一个状态的概率设为未知数。
方程?
(P_{a在i,b在j}-sum P_{ain i的邻点,bin i的邻点状态转移至此的概率}=0)
懒得详写分类讨论)
注意不要从已相遇状态转移过来就成。

void Gauss()
{
    fp(i,1,tot)
    {
        re int now=i;
        fp(j,i+1,tot) if(fabs(a[j][i])+eps>fabs(a[now][i])) now=j;
        if(now^i) swap(a[now],a[i]);
        fp(j,i+1,tot)
        fq(k,tot+1,i)
          a[j][k]-=a[i][k]*a[j][i]/a[i][i];
    }
    fq(i,tot,1)
    {
        fq(j,tot,i+1) a[i][tot+1]-=a[j][tot+1]*a[i][j];
        a[i][tot+1]/=a[i][i];
    }
}
int main()
{
  n=gi();m=gi();A=gi();B=gi();
  fp(i,1,m)
  {
      re int u=gi(),v=gi();
      d[u][v]=d[v][u]=1;++in[u];++in[v];
  }
  fp(i,1,n) scanf("%lf",&p[i]),d[i][i]=1;
  fp(i,1,n) fp(j,1,n) id[i][j]=++tot;
  a[id[A][B]][tot+1]=1;
  fp(i,1,n)
    fp(j,1,n)
    {
      a[id[i][j]][id[i][j]]=1;
      fp(ii,1,n)
        fp(jj,1,n)
          if(d[ii][i]&&d[jj][j]&&ii!=jj)//ii!=jj
          {
              re double p1,p2;
              if(i==ii) p1=p[ii];else p1=(1-p[ii])/in[ii];
              if(j==jj) p2=p[jj];else p2=(1-p[jj])/in[jj];
              a[id[i][j]][id[ii][jj]]+=-p1*p2;//+=???
          }
    }
  Gauss();
  fp(i,1,n) printf("%.6lf ",a[id[i][i]][tot+1]);
  return 0;
}

T7 Luogu3164 [CQOI2014]和谐矩阵

   我们称一个由0和1组成的矩阵是和谐的,当且仅当每个元素都有偶数个相邻的1。一个元素相邻的元素包括它本身,及他上下左右的4个元素(如果存在)。给定矩阵的行数和列数,请计算并输出一个和谐的矩阵。注意:所有元素为0的矩阵是不允许的。

直接上方程啊。
啥?输出全为(0)?把方程里的自由元赋为(1)即可.

int main()
{
    n=gi();m=gi();tot=n*m;
    fp(i,1,n)
    fp(j,1,m)
        {
            re int p=pos(i,j),l=pos(i,j-1),r=pos(i,j+1),u=pos(i-1,j),d=pos(i+1,j);
            a[p][p]=1;
            if (i>1) a[p][u]=1;
            if (j>1) a[p][l]=1;
            if (i<n) a[p][d]=1;
            if (j<m) a[p][r]=1;
        }
    fp(i,1,tot)
    {
        if (!a[i][i])
        {
            fp(j,i+1,tot)
                if (a[j][i]) {swap(a[i],a[j]);break;}
        }
          fp(j,i+1,tot)
            if (a[j][i]) a[j]^=a[i];
    }
    fq(i,tot,1)
    {
        ans[i]=a[i][tot+1];
        fq(j,tot,i+1)
            if (a[i][j]) ans[i]^=ans[j];
        if (!a[i][i]) ans[i]=1;
    }
    for (int i=1;i<=n;++i,puts(""))
        fp(j,1,m)
            printf("%d ",ans[pos(i,j)]);
    return 0;
}

T8 Luogu3265 [JLOI2015]装备购买

(n)个装备,每个装备(m)个属性,每个装备还有个价格。如果手里有的装备的每一项属性为它们分配系数(实数)后可以相加得到某件装备,则不必要买这件装备。求最多装备下的最小花费。

看到这道题可以想起线性基的性质:其中没有一个元素能被其它元素异或和求得。
那这题也类似?可以拿线性基的(insert)的方法套?
线性基里存(m)维,拿一个表达式进去时,若该表达式对应维系数为0就换维,如果该维没访问过就把这个式子整个塞进去,否则就把这个式子当前维消掉(高斯消元)。
于是,式子只有两个结果,一个是被塞进去,另一个是被消成蛋。
(竟然卡精度)

il int Insert(re int x)
{
    fp(i,1,m)
    {
        if(fabs(a[x].s[i])<=eps) continue;
        if(vis[i]) fq(j,m,i) a[x].s[j]-=p[i][j]*a[x].s[i]/p[i][i];
        else {vis[i]=1;fp(j,i,m) p[i][j]=a[x].s[j];return 1;}
    }
    return 0;
}
int main()
{
    n=gi();m=gi();
    fp(i,1,n) fp(j,1,m) a[i].s[j]=gi();
    fp(i,1,n) a[i].c=gi();
    sort(a+1,a+1+n);
    //fp(i,1,n) printf("%d %d %d
",a[i].s[1],a[i].s[2],a[i].s[3]);
    fp(i,1,n)
    if(Insert(i)) ++tot,ans+=a[i].c;
    printf("%d %d
",tot,ans);
    return 0;
}

免责声明:文章转载自《高斯消元总结》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇java连接redis中的数据查、增、改、删操作的方法如何把C盘里的文件默认位置更改到D盘指定目录?下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

高斯分布(Gaussian Distribution)的概率密度函数(probability density function)

高斯分布(Gaussian Distribution)的概率密度函数(probability density function) 对应于numpy中: numpy.random.normal(loc=0.0, scale=1.0, size=None) 参数的意义为: loc:float 此概率分布的均值(对应着整个分布的中心centre) scale...

两个多维高斯分布之间的KL散度推导

  在深度学习中,我们通常对模型进行抽样并计算与真实样本之间的损失,来估计模型分布与真实分布之间的差异。并且损失可以定义得很简单,比如二范数即可。但是对于已知参数的两个确定分布之间的差异,我们就要通过推导的方式来计算了。   下面对已知均值与协方差矩阵的两个多维高斯分布之间的KL散度进行推导。当然,因为便于分布之间的逼近,Wasserstein dista...

正态分布(Normal distribution)也称“常态分布”,又名高斯分布

常用希腊字母符号: 正态分布公式 曲线可以表示为:称x服从正态分布,记为 X~N(m,s2),其中μ为均值,s为标zhuan准差,X∈(-∞,+ ∞ )。 其中 根号2侧部分  可以看成 密度函数的积分为1,你就可以看成为了凑出来1特意设置的 一个 框架 无实际意义。 标准正态分布另正态分布的μ为0,s为1。  判断一组数是否符合正态分布主要看 P...

paper 62:高斯混合模型(GMM)参数优化及实现

高斯混合模型(GMM)参数优化及实现 (< xmlnamespace prefix ="st1" ns ="urn:schemas-microsoft-com:office:smarttags" />2010-11-13) 1 高斯混合模型概述< xmlnamespace prefix ="o" ns ="urn:schemas-micr...

常见的聚类算法

常见的聚类算法 1. K-Means(K均值)聚类 算法步骤: (1) 首先我们选择一些类/组,并随机初始化它们各自的中心点。中心点是与每个数据点向量长度相同的位置。这需要我们提前预知类的数量(即中心点的数量)。 (2) 计算每个数据点到中心点的距离,数据点距离哪个中心点最近就划分到哪一类中。 (3) 计算每一类中中心点作为新的中心点。 (4) 重复以上步...

几种常见随机过程

1. 高斯随机过程 没太多要说的;要注意的是高斯随机过程不仅要求幅度是高斯分布的,还要求所有高阶密度函数都是高斯的。 2. 白噪声 功率谱为常数,相关函数为冲击。注意一般应用场合下还要限定白噪声的分布,如高斯白噪声。 $S(jomega)=A$ $R( au)=Adelta( au)$ 白噪声的相关函数表明该过程“跳变”无限快,具有无限方差。用“White...