POJ-2065 SETI 高斯消元

  题目连接:http://poj.org/problem?id=2065

  高斯消元求出上三角矩阵后,求出 a×x = b(mod p),即 a×x - p×y=b,用扩展欧几里得求出x。

  1 //STATUS:C++_AC_32MS_156KB
  2 #include <functional>
  3 #include <algorithm>
  4 #include <iostream>
  5 //#include <ext/rope>
  6 #include <fstream>
  7 #include <sstream>
  8 #include <iomanip>
  9 #include <numeric>
 10 #include <cstring>
 11 #include <cassert>
 12 #include <cstdio>
 13 #include <string>
 14 #include <vector>
 15 #include <bitset>
 16 #include <queue>
 17 #include <stack>
 18 #include <cmath>
 19 #include <ctime>
 20 #include <list>
 21 #include <set>
 22 #include <map>
 23 using namespace std;
 24 //using namespace __gnu_cxx;
 25 //define
 26 #define pii pair<int,int>
 27 #define mem(a,b) memset(a,b,sizeof(a))
 28 #define lson l,mid,rt<<1
 29 #define rson mid+1,r,rt<<1|1
 30 #define PI acos(-1.0)
 31 //typedef
 32 typedef long long LL;
 33 typedef unsigned long long ULL;
 34 //const
 35 const int N=73;
 36 const int INF=0x3f3f3f3f;
 37 const int MOD=100000,STA=8000010;
 38 const LL LNF=1LL<<60;
 39 const double EPS=1e-8;
 40 const double OO=1e15;
 41 const int dx[4]={-1,0,1,0};
 42 const int dy[4]={0,1,0,-1};
 43 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
 44 //Daily Use ...
 45 inline int sign(double x){return (x>EPS)-(x<-EPS);}
 46 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
 47 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
 48 template<class T> inline T lcm(T a,T b,T d){return a/d*b;}
 49 template<class T> inline T Min(T a,T b){return a<b?a:b;}
 50 template<class T> inline T Max(T a,T b){return a>b?a:b;}
 51 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
 52 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
 53 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}
 54 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}
 55 //End
 56 
 57 int A[N][N];//增广矩阵
 58 int B[N];//解集
 59 bool free_x[N];//标记是否是不确定的变元
 60 int T,n,m,k,p;
 61 
 62 //
 63 void Debug(int equ,int var)
 64 {
 65     int i, j;
 66     for(i=0;i<equ;i++){
 67         for(j=0;j<=var;j++)
 68             printf("%4d",A[i][j]);
 69         putchar('\n');
 70     }
 71     putchar('\n');
 72 }
 73 //
 74 
 75 void extgcd(int a,int b,int &d,int &x,int &y)
 76 {
 77     if(!b){d=a;x=1;y=0;}
 78     else {extgcd(b,a%b,d,y,x);y-=x*(a/b);}
 79 }
 80 
 81 inline int gcd(int a,int b)
 82 {
 83     int t;
 84     while(b!=0)
 85     {
 86         t=b;
 87         b=a%b;
 88         a=t;
 89     }
 90     return a;
 91 }
 92 
 93 inline int lcm(int a,int b)
 94 {
 95     return a/gcd(a,b)*b;//先除后乘防溢出
 96 }
 97 
 98 // 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,但无整数解,
 99 //-1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数)
100 //有equ个方程,var个变元。增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var.
101 int Gauss(int equ,int var)
102 {
103     int i,j,k;
104     int max_r; // 当前这列绝对值最大的行.
105     int col; //当前处理的列
106     int ta,tb;
107     int LCM;
108     int temp;
109     int free_x_num;
110     int free_index;
111 
112     for(int i=0;i<=var;i++)
113     {
114         B[i]=0;
115         free_x[i]=true;
116     }
117     //转换为阶梯阵.
118     col=0; // 当前处理的列
119     for(k = 0;k < equ && col < var;k++,col++)
120     {// 枚举当前处理的行.
121 // 找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差)
122         max_r=k;
123         for(i=k+1;i<equ;i++)
124         {
125             if(abs(A[i][col])>abs(A[max_r][col])) max_r=i;
126         }
127         if(max_r!=k)
128         {// 与第k行交换.
129             for(j=k;j<var+1;j++) swap(A[k][j],A[max_r][j]);
130         }
131         if(A[k][col]==0)
132         {// 说明该col列第k行以下全是0了,则处理当前行的下一列.
133             k--;
134             continue;
135         }
136         for(i=k+1;i<equ;i++)    //  i=0高斯约当消元,才能在多解的情况下判断变元是否确定
137         {// 枚举要删去的行.
138             if(A[i][col]!=0 && i!=k)
139             {
140                 LCM = lcm(abs(A[i][col]),abs(A[k][col]));
141                 ta = LCM/abs(A[i][col]);
142                 tb = LCM/abs(A[k][col]);
143                 if(A[i][col]*A[k][col]<0)tb=-tb;//异号的情况是相加
144                 for(j=0;j<=var;j++)
145                 {
146                     A[i][j] = (A[i][j]*ta - A[k][j]*tb)%p;
147                 }
148             }
149         }
150     }
151 
152   //  Debug(equ,var);
153 
154     // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).
155     /*
156     for (i = k; i < equ; i++)
157     {
158         if (A[i][col] != 0) return -1;
159     }
160     // 对于无穷解来说,如果要判断哪些是自由变元,那么初等行变换中的交换就会影响,则要记录交换.
161     // 2. 无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.
162     // 且出现的行数即为自由变元的个数.
163     if (k < var)return 1;
164     {
165         // 首先,自由变元有var - k个,即不确定的变元至少有var - k个.
166         for (i = k - 1; i >= 0; i--)
167         {
168             // 第i行一定不会是(0, 0, ..., 0)的情况,因为这样的行是在第k行到第equ行.
169             // 同样,第i行一定不会是(0, 0, ..., a), a != 0的情况,这样的无解的.
170             free_x_num = 0; // 用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元.
171             for (j = 0; j < var; j++)
172             {
173                 if (A[i][j] != 0 && free_x[j]) free_x_num++, free_index = j;
174             }
175             if (free_x_num > 1) continue; // 无法求解出确定的变元.
176             // 说明就只有一个不确定的变元free_index,那么可以求解出该变元,且该变元是确定的.
177             temp = A[i][var];
178             for (j = 0; j < var; j++)
179             {
180                 if (A[i][j] != 0 && j != free_index) temp -= A[i][j] * x[j];
181             }
182             x[free_index] = temp / A[i][free_index]; // 求出该变元.
183             free_x[free_index] = 0; // 该变元是确定的.
184         }
185         return var - k; // 自由变元有var - k个.
186     }*/
187     // 3. 唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵.
188     // 计算出Xn-1, Xn-2 ... X0.
189     for (i = var - 1; i >= 0; i--)
190     {
191         temp = A[i][var];
192         for (j = i + 1; j < var; j++)
193         {
194             if (A[i][j] != 0) temp = (temp-(A[i][j] * B[j]))%p;
195         }
196    //     if (temp % A[i][i] != 0) return -2; // 说明有浮点数解,但无整数解.
197         int x,y,d;
198         extgcd(A[i][i],p,d,x,y);
199         B[i]=((x*(temp/d))%p+p)%p;
200      //   x[i] = (temp / A[i][i])%p;
201     }
202     return 0;
203 }
204 
205 int main()
206 {
207  //   freopen("in.txt","r",stdin);
208     int i,j,t;
209     char s[N];
210     scanf("%d",&T);
211     while(T--)
212     {
213         scanf("%d%s",&p,s);
214         n=strlen(s);
215         for(i=0;i<n;i++){
216             t=1;
217             for(j=0;j<n;j++){
218                 A[i][j]=t;
219                 t=(t*(i+1))%p;
220             }
221             A[i][j]=s[i]=='*'?0:s[i]-'a'+1;
222         }
223 
224         Gauss(n,n);
225      //   Debug(n,n);
226 
227         printf("%d",B[0]);
228         for(i=1;i<n;i++)
229             printf(" %d",B[i]);
230         putchar('\n');
231     }
232     return 0;
233 }

 

posted @ 2013-05-31 00:58  zhsl  阅读(207)  评论(0编辑  收藏  举报