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 }

 

你可能感兴趣的:(set)