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 个方程式,然后使用高斯消元来解此方程组即可。

上面这段话转自:http://www.cnblogs.com/gj-Acit/p/3903085.html

代码:

  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 }

时间: 2024-10-17 17:03:18

poj2947(高斯消元解同模方程组)的相关文章

【poj2947】高斯消元求解同模方程组【没有AC,存代码】

题意: p start enda1,a2......ap (1<=ai<=n)第一行表示从星期start 到星期end 一共生产了p 件装饰物(工作的天数为end-start+1+7*x,加7*x 是因为它可能生产很多周),第二行表示这p 件装饰物的种类(可能出现相同的种类,即ai=aj).规定每件装饰物至少生产3 天,最多生产9 天.问每种装饰物需要生产的天数.如果没有解,则输出"Inconsistent data.",如果有多解,则输出"Multiple so

POJ2947Widget Factory(高斯消元解同模方程)

http://poj.org/problem?id=2947 题目大意:有n 种装饰物,m 个已知条件,每个已知条件的描述如下:p start enda1,a2......ap (1<=ai<=n)第一行表示从星期start 到星期end 一共生产了p 件装饰物(工作的天数为end-start+1+7*x,加7*x 是因为它可能生产很多周),第二行表示这p 件装饰物的种类(可能出现相同的种类,即ai=aj).规定每件装饰物至少生产3 天,最多生产9 天.问每种装饰物需要生产的天数.如果没有解,

Poj 2947 widget factory (高斯消元解同模方程)

题目连接: http://poj.org/problem?id=2947 题目大意: 有n种类型的零件,m个工人,每个零件的加工时间是[3,9],每个工人在一个特定的时间段内可以生产k个零件(可以相同种类,也可以不同种类),问每种零件生产一个出来需要的时间? 解题思路: 给出的时间段是从周几到周几,并没有给出具体的时间段,因此在计算过程中要进行取模,还有就是对每个零件要在题目要求的范围内进行枚举. ps:如果求出来的增广矩阵是n*n的,但是某个零件在[3,9]之间没有合理的解,也是无解的. 1

【高斯消元解XOR方程】POJ1222-EXTENDED

[题目大意] 有5*6盏灯,每次开/关一个灯,上下左右的灯状态也会反转.问怎么使状态统一? [思路] 典型高斯消元解XOR方程,注意每盏灯要么0次要么1次. 1 #include <iostream> 2 #include <stdio.h> 3 #include <algorithm> 4 #include <set> 5 using namespace std; 6 int a[40][40]; 7 void gauss() 8 { 9 int i,j,

poj1830(高斯消元解mod2方程组)

题目链接:http://poj.org/problem?id=1830 题意:中文题诶- 思路:高斯消元解 mod2 方程组 有 n 个变元,根据给出的条件列 n 个方程组,初始状态和终止状态不同的位置对应的方程右边常数项为1,状态相同的位置对于的方程组右边的常数项为0.然后用高斯消元解一下即可.若有唯一解输出1即可,要是存在 k 个变元,则答案为 1 << k, 因为每个变元都有01两种选择嘛- 代码: 1 #include <iostream> 2 #include <s

poj1753(高斯消元解mod2方程组)

题目链接:http://poj.org/problem?id=1753 题意:一个 4*4 的棋盘,初始时上面放满了黑色或白色的棋子.对 (i, j) 位置进行一次操作后 (i, j), (i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1) 位置的棋子会变成原来相反的状态.问最少需要多少步可以将棋盘上的棋子全部变成白色或者黑色. 思路:分别将棋子变成黑色和白色,然后再用高斯消元解,其中步数较小者即为答案. 注意不存在唯一解时需要枚举自由变元来取得最小步数.

【高斯消元解xor方程】BZOJ1923-[Sdoi2010]外星千足虫

[题目大意] 有n个数或为奇数或为偶数,现在进行m次操作,每次取出部分求和,告诉你这几次操作选取的数和它们和的奇偶性.如果通过这m次操作能得到所有数的奇偶性,则输出进行到第n次时即可求出答案:否则输出无法确定. [思路] 高斯消元解xor方程组,求最少需要的方程个数或判断无法确定. 无法确定即存在自由元,在每次操作中找1的时候判断一下就好了:最小方程个数,就是记录下每次找到的最小的1的位置,最后输出最大值即可. [错误] 忘记把ans改为-1了(见程序注释) [备注] P.S.我看别人在高斯消元

BZOJ 3563 DZY Loves Chinese / BZOJ 3569 DZY Loves Chinese II 随机化+高斯消元解异或方程组

题目大意:给出一个无向图,问删掉k条边的时候,图是否联通. 思路:虽然我把这两个题放在了一起,但是其实这两个题可以用完全不同的两个解法来解决. 第一个题其实是DZY出错了...把每次的边数也异或了,那就直接用这个性质一个一个往后推就行了..最后一个暴力求一下.. 第二个题才是本意啊. 听到做法的时候我惊呆了.. 首先是将整个图中拆出一个树,那么所有边就分为树边和非树边.将所有非树边都加一个随机权值.树边的权值是所有能够覆盖它的非树边的权值的异或和. 把整个图拆开的充要条件是拆掉一条树边,同时将所

POJ 2947-Widget Factory(高斯消元解同余方程式)

题目地址:id=2947">POJ 2947 题意:N种物品.M条记录,接写来M行,每行有K.Start,End,表述从星期Start到星期End,做了K件物品.接下来的K个数为物品的编号. 此题注意最后结果要调整到3-9之间. 思路: 非常easy想到高斯消元. 可是是带同余方程式的高斯消元,開始建立关系的时候就要MOD 7 解此类方程式时最后求解的过程要用到扩展gcd的思想,举个样例,假设最后得到的矩阵为: 1  1   4 0  6   4 则6 * X2 % 7= 4 % 7  则