题目连接:http://poj.org/problem?id=2947
求解形如:
a11×x11%p+a12×x12%p+......+a1n×x1n%p=k1%p
a21×x21%p+a22×x22%p+......+a2n×x2n%p=k2%p
......
an1×xn1%p+an2×xn2%p+......+ann×xnn%p=kn%p
直接取模求解线性方程组。在网上找了一个整数Gauss的模板,貌似网上很多都是用的这个,但这个模板在多解情况下求变元是否确定有问题,应该用高斯-约当消元求出最简的上三角矩阵:
2 1 -1 8 1 0 0 2
-3 -1 2 -11 ——> 0 1 0 3
-2 1 2 -3 0 0 1 -1
那么这样就可以在O(n)的时间内判断变元是否确定。
1 //STATUS:C++_AC_2657MS_452KB 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=310; 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 x[N];//解集 59 bool free_x[N];//标记是否是不确定的变元 60 int n,m,k; 61 62 // 63 void Debug(int equ,int var) 64 { 65 int i, j; 66 for (i = 0; i < equ; i++) 67 { 68 for (j = 0; j < var + 1; j++) 69 { 70 cout << a[i][j] << " "; 71 } 72 cout << endl; 73 } 74 cout << endl; 75 } 76 // 77 78 inline int gcd(int a,int b) 79 { 80 int t; 81 while(b!=0) 82 { 83 t=b; 84 b=a%b; 85 a=t; 86 } 87 return a; 88 } 89 inline int lcm(int a,int b) 90 { 91 return a/gcd(a,b)*b;//先除后乘防溢出 92 } 93 94 // 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,但无整数解, 95 //-1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数) 96 //有equ个方程,var个变元。增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var. 97 int Gauss(int equ,int var) 98 { 99 int i,j,k; 100 int max_r; // 当前这列绝对值最大的行. 101 int col; //当前处理的列 102 int ta,tb; 103 int LCM; 104 int temp; 105 int free_x_num; 106 int free_index; 107 108 for(int i=0;i<=var;i++) 109 { 110 x[i]=0; 111 free_x[i]=true; 112 } 113 114 //转换为阶梯阵. 115 col=0; // 当前处理的列 116 for(k = 0;k < equ && col < var;k++,col++) 117 {// 枚举当前处理的行. 118 // 找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差) 119 max_r=k; 120 for(i=k+1;i<equ;i++) 121 { 122 if(abs(a[i][col])>abs(a[max_r][col])) max_r=i; 123 } 124 if(max_r!=k) 125 {// 与第k行交换. 126 for(j=k;j<var+1;j++) swap(a[k][j],a[max_r][j]); 127 } 128 if(a[k][col]==0) 129 {// 说明该col列第k行以下全是0了,则处理当前行的下一列. 130 k--; 131 continue; 132 } 133 for(i=0;i<equ;i++) 134 {// 枚举要删去的行. 135 if(a[i][col]!=0 && i!=k) 136 { 137 LCM = lcm(abs(a[i][col]),abs(a[k][col])); 138 ta = LCM/abs(a[i][col]); 139 tb = LCM/abs(a[k][col]); 140 if(a[i][col]*a[k][col]<0)tb=-tb;//异号的情况是相加 141 for(j=0;j<var+1;j++) 142 { 143 a[i][j] = ((a[i][j]*ta-a[k][j]*tb)%7+7)%7; 144 } 145 } 146 } 147 } 148 149 // Debug(equ,var); 150 151 // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0). 152 for (i = k; i < equ; i++) 153 { 154 if (a[i][col] != 0) return -1; 155 } 156 // 对于无穷解来说,如果要判断哪些是自由变元,那么初等行变换中的交换就会影响,则要记录交换. 157 // 2. 无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵. 158 // 且出现的行数即为自由变元的个数. 159 if (k < var)return 1; 160 /* { 161 // 首先,自由变元有var - k个,即不确定的变元至少有var - k个. 162 for (i = k - 1; i >= 0; i--) 163 { 164 // 第i行一定不会是(0, 0, ..., 0)的情况,因为这样的行是在第k行到第equ行. 165 // 同样,第i行一定不会是(0, 0, ..., a), a != 0的情况,这样的无解的. 166 free_x_num = 0; // 用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元. 167 for (j = 0; j < var; j++) 168 { 169 if (a[i][j] != 0 && free_x[j]) free_x_num++, free_index = j; 170 } 171 if (free_x_num > 1) continue; // 无法求解出确定的变元. 172 // 说明就只有一个不确定的变元free_index,那么可以求解出该变元,且该变元是确定的. 173 temp = a[i][var]; 174 for (j = 0; j < var; j++) 175 { 176 if (a[i][j] != 0 && j != free_index) temp -= a[i][j] * x[j]; 177 } 178 x[free_index] = temp / a[i][free_index]; // 求出该变元. 179 free_x[free_index] = 0; // 该变元是确定的. 180 } 181 return var - k; // 自由变元有var - k个. 182 }*/ 183 // 3. 唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵. 184 // 计算出Xn-1, Xn-2 ... X0. 185 /* 186 for (i = var - 1; i >= 0; i--) 187 { 188 temp = a[i][var]; 189 for (j = i + 1; j < var; j++) 190 { 191 if (a[i][j] != 0) temp -= a[i][j] * x[j]; 192 } 193 if (temp % a[i][i] != 0) return -2; // 说明有浮点数解,但无整数解. 194 x[i] = temp / a[i][i]; 195 }*/ 196 return 0; 197 } 198 199 map<string,int> q; 200 201 int main() 202 { 203 // freopen("in.txt","r",stdin); 204 int i,j,num,ans; 205 char s[10],e[10]; 206 int cnt[N]; 207 q["MON"]=1,q["TUE"]=2,q["WED"]=3, 208 q["THU"]=4,q["FRI"]=5,q["SAT"]=6,q["SUN"]=7; 209 while(~scanf("%d%d",&n,&m) && (n || m)) 210 { 211 for(i=0;i<m;i++){ 212 mem(cnt,0); 213 scanf("%d%s%s",&k,s,e); 214 while(k--){ 215 scanf("%d",&num); 216 cnt[num-1]++; 217 } 218 for(j=0;j<n;j++) 219 a[i][j]=cnt[j]%7; 220 if(q[s]<=q[e])a[i][n]=(q[e]-q[s]+1)%7; 221 else a[i][n]=(8-q[s]+q[e])%7; 222 } 223 // Debug(m,n); 224 225 ans=Gauss(m,n); 226 227 if(ans==0){ 228 for(i=0;i<n;i++){ 229 for(j=3;j<=9;j++) 230 if(a[i][i]*j%7==a[i][n]){ 231 x[i]=j; 232 break; 233 } 234 } 235 printf("%d",x[0]); 236 for(i=1;i<n;i++) 237 printf(" %d",x[i]); 238 } 239 else if(ans==-1)printf("Inconsistent data."); 240 else printf("Multiple solutions."); 241 putchar('\n'); 242 } 243 return 0; 244 }