[关闭]
@zhangche0526 2017-02-25T06:31:37.000000Z 字数 2581 阅读 793

高斯消元


  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<algorithm>
  6. using namespace std;
  7. const int MAXN=100;
  8. int x[MAXN+1];//解集
  9. int a[MAXN+1][MAXN+1];//矩阵
  10. bool free_x[MAXN+1];//标记是否是不确定的变元
  11. inline int gcd(int a,int b){int t;while(b!=0){t=b;b=a%b;a=t;}return a;}//最大公约数
  12. inline int lcm(int a,int b){return a/gcd(a,b)*b;}//先除后乘防溢出,最小公倍数
  13. /* 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,但无整数解,
  14. -1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数)
  15. 有equ个方程,var个变元。增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var.*/
  16. int guess(int equ,int var)
  17. {
  18. int i,j,k;
  19. int rowmax;//当前这列绝对值最大的行
  20. int col;//当前处理的列
  21. int ta,tb;
  22. int LCM;
  23. int temp;
  24. int free_x_num;
  25. int free_index;
  26. int max_r;
  27. memset(x,0,var+1);
  28. memset(free_x,true,var+1);
  29. col=1;
  30. for(k=1;k<=equ&&col<=var;k++,col++)//转换为阶梯阵
  31. {
  32. max_r=k;
  33. for(i=k+1;i<equ;i++)
  34. {
  35. if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
  36. }
  37. if(max_r!=k)
  38. {// 与第k行交换.
  39. for(j=k;j<var+1;j++) swap(a[k][j],a[max_r][j]);
  40. }
  41. if(a[k][col]==0)
  42. {// 说明该col列第k行以下全是0了,则处理当前行的下一列.
  43. k--;continue;
  44. }
  45. for(i=k+1;i<=equ;i++)
  46. {
  47. if(a[i][col]!=0)
  48. {
  49. LCM = lcm(abs(a[i][col]),abs(a[k][col]));
  50. ta = LCM/abs(a[i][col]);
  51. tb = LCM/abs(a[k][col]);
  52. if(a[i][col]*a[k][col]<0)tb=-tb;//异号的情况是相加
  53. for(j=col+1;j<=var+1;j++)
  54. {
  55. a[i][j] = a[i][j]*ta-a[k][j]*tb;
  56. }
  57. }
  58. }
  59. }
  60. // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).
  61. for (i = k; i < equ; i++)
  62. { // 对于无穷解来说,如果要判断哪些是自由变元,那么初等行变换中的交换就会影响,
  63. //则要记录交换.
  64. if (a[i][col] != 0) return -1;
  65. }
  66. // 2. 无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,
  67. //即说明没有形成严格的上三角阵.
  68. // 且出现的行数即为自由变元的个数.
  69. if (k < var)
  70. {
  71. // 首先,自由变元有var - k个,即不确定的变元至少有var - k个.
  72. for (i = k - 1; i >= 0; i--)
  73. {
  74. // 第i行一定不会是(0, 0, ..., 0)的情况,因为这样的行是在第k行到第equ行.
  75. // 同样,第i行一定不会是(0, 0, ..., a), a != 0的情况,这样的无解的.
  76. free_x_num = 0; // 用于判断该行中的不确定的变元的个数,如果超过1个,
  77. //则无法求解,它们仍然为不确定的变元.
  78. for (j = 0; j < var; j++)
  79. {
  80. if (a[i][j] != 0 && free_x[j]) free_x_num++, free_index = j;
  81. }
  82. if (free_x_num > 1) continue; // 无法求解出确定的变元.
  83. // 说明就只有一个不确定的变元free_index,那么可以求解出该变元,
  84. //且该变元是确定的.
  85. temp = a[i][var];
  86. for (j = 0; j < var; j++)
  87. {
  88. if (a[i][j] != 0 && j != free_index) temp -= a[i][j] * x[j];
  89. }
  90. x[free_index] = temp / a[i][free_index]; // 求出该变元.
  91. free_x[free_index] = 0; // 该变元是确定的.
  92. }
  93. return var - k; // 自由变元有var - k个.
  94. }
  95. // 3. 唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵.
  96. // 计算出Xn-1, Xn-2 ... X0.
  97. for (i = var - 1; i >= 0; i--)
  98. {
  99. temp = a[i][var];
  100. for (j = i + 1; j < var; j++)
  101. {
  102. if (a[i][j] != 0) temp -= a[i][j] * x[j];
  103. }
  104. if (temp % a[i][i] != 0) return -2; // 说明有浮点数解,但无整数解.
  105. x[i] = temp / a[i][i];
  106. }
  107. }
  108. int main()
  109. {
  110. int i, j;
  111. int equ,var;
  112. while (scanf("%d %d", &equ, &var) != EOF)
  113. {
  114. memset(a, 0, sizeof(a));
  115. for (i = 1; i <= equ; i++)
  116. {
  117. for (j = 1; j <= var + 1; j++)
  118. {
  119. scanf("%d", &a[i][j]);
  120. }
  121. }
  122. int free_num = guess(equ,var);
  123. if (free_num == -1) printf("无解!\n");
  124. else if (free_num == -2) printf("有浮点数解,无整数解!\n");
  125. else if (free_num > 0)
  126. {
  127. printf("无穷多解! 自由变元个数为%d\n", free_num);
  128. for (i = 1; i <= var; i++)
  129. {
  130. if (free_x[i]) printf("x%d 是不确定的\n", i);
  131. else printf("x%d: %d\n", i, x[i]);
  132. }
  133. }
  134. else
  135. {
  136. for (i = 1; i <= var; i++)
  137. {
  138. printf("x%d: %d\n", i, x[i]);
  139. }
  140. }
  141. printf("\n");
  142. }
  143. return 0;
  144. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注