poj2947(高斯消元解同模方程组)

题目链接:http://poj.org/problem?id=2947

 

题意:有n 种装饰物,m 个已知条件,每个已知条件的描述如下:

p start end
a1, a2......ap (1<= ai <= n)
第一行表示从星期 start 到星期 end 一共生产了p 件装饰物 (工作的天数为end - start + 1 + 7*x, 加 7*x 是因为它可能生产很多周),第二行表示这 p 件装饰物的种类(可能出现相同的种类,即 ai = aj)。规定每件装饰物至少生产3 天,最多生产9 天。问每种装饰物需要生产的天数。如果没有解,则输出“Inconsistent data.”,如果有多解,则输出“Multiple solutions.”,如果只有唯一解,则输出每种装饰物需要生产的天数。
 
思路:高斯消元接同模方程组
设每种装饰物需要生产的天数为 xi(1<=i<=n)。每一个条件就相当于给定了一个方程式,假设生产1 类装饰物 a1 件、2 类装饰物 a2 件、i 类装饰物 ai 件所花费的天数为 b = end - star + 1 + 7 * x,则可以列出下列方程:
a1 * x1 + a2 * x2 +...an * xn = b (mod 7)
这样一共可以列出m 个方程式,然后使用高斯消元来解此方程组即可。
 
 
代码:
  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <algorithm>
  4 #include <string.h>
  5 #include <math.h>
  6 using namespace std;
  7 
  8 const int MAXN = 4e2;
  9 const int mod = 7;
 10 bool free_x[MAXN];
 11 int a[MAXN][MAXN];
 12 int x[MAXN];
 13 
 14 inline int gcd(int a, int b){
 15     int t;
 16     while(b != 0){
 17         t = b;
 18         b = a % b;
 19         a = t;
 20     }
 21     return a;
 22 }
 23 
 24 inline int lcm(int a, int b){
 25     return a / gcd(a, b) * b;
 26 }
 27 
 28 //返回-1表示无解,0表示有唯一解,大于0表示无穷解并返回变元个数
 29 int Gauss(int equ, int var){//equ为方程数,var为未知数个数
 30     int i, j, k;
 31     int max_r;//当前列绝对值最大的行
 32     int col;//当前处理的列
 33     int ta, tb;
 34     int LCM;
 35     int temp;
 36     int free_x_num;
 37     int free_index;
 38     for(int i = 0; i <= var; i++){
 39         x[i] = 0;
 40         free_x[i] = true;//初始化全部为变元
 41     }
 42     for(k = 0, col = 0; k < equ && col < var; k++, col++){
 43         //枚举当前处理的行k
 44         //找到当前col列元素绝对值最大的行与第k行交换
 45         max_r = k;
 46         for(i = k + 1; i < equ; i++){
 47             if(abs(a[i][col] > abs(a[max_r][col]))) max_r = i;//记录当前列中最大值所在行
 48         }
 49         if(max_r != k){//与第k行交换
 50             for(int j = k; j < var + 1; j++){
 51                 swap(a[k][j], a[max_r][j]);
 52             }
 53         }
 54         if(a[k][col] == 0){//说明col列中第k行以下全是0了,则处理当前下一行
 55             k--;
 56             continue;
 57         }
 58         for(i = k + 1; i < equ; i++){//枚举要删去的行
 59             if(a[i][col] != 0){
 60                 LCM = lcm(abs(a[i][col]), abs(a[k][col]));
 61                 ta = LCM / abs(a[i][col]);
 62                 tb = LCM / abs(a[k][col]);
 63                 if(a[i][col] * a[k][col] < 0) tb = -tb;
 64                 for(j = col; j < var + 1; j++){
 65                     a[i][j] = ((a[i][j] * ta - a[k][j] * tb) % mod + mod) % mod;
 66                 }
 67             }
 68         }
 69     }
 70     //无解的情况,化简的增广矩阵中存在(0,0,...1)这样的行(a!=0)
 71     for(i = k; i < equ; i++){
 72         if(a[i][col] != 0) return -1;
 73     }
 74     //无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.
 75     //且出现的行数即为自由变元的个数.
 76     if(k < var){
 77         for(i = k - 1; i >= 0; i--){
 78             // 第i行一定不会是(0, 0, ..., 0)的情况,因为这样的行是在第k行到第equ行.
 79             // 同样,第i行一定不会是(0, 0, ..., a), a != 0的情况,这样的无解的.
 80             free_x_num = 0;//用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元.
 81             for(j = 0; j < var; j++){
 82                 if(a[i][j] && free_x[j]) free_x_num++, free_index = j;
 83             }
 84             if(free_x_num > 1) continue;//无法求解出确定的变元
 85             // 说明就只有一个不确定的变元free_index,那么可以求解出该变元,且该变元是确定的
 86             temp = a[i][var];
 87             for(j = 0; j < var; j++){
 88                 if(a[i][j] != 0 && j != free_index) temp -= a[i][j] * x[j] % mod;
 89                 temp = (temp % mod + mod) % mod;
 90             }
 91             x[free_index] = (temp / a[i][free_index]) % mod;//求出该变元
 92             free_x[free_index] = 0;//该变元已经确定,取消对应变元标记
 93         }
 94         return var - k;//自由变元有var-k个
 95     }
 96     //唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵.
 97     //计算出Xn-1, Xn-2 ... X0.
 98     for(i = var - 1; i >= 0; i--){
 99         temp = a[i][var];
100         for(j = i + 1; j < var; j++){
101             if(a[i][j] != 0) temp -= a[i][j] * x[j];
102             temp = (temp % mod + mod) % mod;
103         }
104         while(temp % a[i][i] != 0) temp += mod;
105         x[i] = (temp /a[i][i]) % mod;
106     }
107     return 0;
108 }
109 
110 int tran(char *s){
111     if(strcmp(s, "MON") == 0) return 1;
112     if(strcmp(s, "TUE") == 0) return 2;
113     if(strcmp(s, "WED") == 0) return 3;
114     if(strcmp(s, "THU") == 0) return 4;
115     if(strcmp(s, "FRI") == 0) return 5;
116     if(strcmp(s, "SAT") == 0) return 6;
117     return 7;
118 }
119 
120 char s1[20], s2[20];
121 
122 int main(void){
123     int n, m, k, t;
124     while(~scanf("%d%d", &n, &m)){
125         if(n + m == 0) break;
126         memset(a, 0, sizeof(a));
127         for(int i = 0; i < m; i++){
128             scanf("%d%s%s", &k, s1, s2);
129             a[i][n] = ((tran(s2) - tran(s1) + 1) % mod + mod) % mod;//方程组的常数项
130             while(k--){
131                 scanf("%d", &t);
132                 t--;
133                 a[i][t]++;
134                 if(a[i][t] >= mod) a[i][t] %= mod;
135             }
136         }
137         int cnt = Gauss(m, n);//m为条件数目即方程数
138         if(cnt == 0){
139             for(int i = 0; i < n; i++){
140                 if(x[i] <= 2) x[i] += 7;//题意要求每件物品最少生产3天,最多生产9天
141                 printf("%d ", x[i]);
142             }
143             puts("");
144         }else if(cnt == -1) puts("Inconsistent data.");
145         else puts("Multiple solutions.");
146     }
147     return 0;
148 }
View Code

 

posted @ 2017-09-23 17:36  geloutingyu  阅读(529)  评论(0编辑  收藏  举报