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 个方程式,然后使用高斯消元来解此方程组即可。
 
 
代码:
 #include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <math.h>
using namespace std; const int MAXN = 4e2;
const int mod = ;
bool free_x[MAXN];
int a[MAXN][MAXN];
int x[MAXN]; inline int gcd(int a, int b){
int t;
while(b != ){
t = b;
b = a % b;
a = t;
}
return a;
} inline int lcm(int a, int b){
return a / gcd(a, b) * b;
} //返回-1表示无解,0表示有唯一解,大于0表示无穷解并返回变元个数
int Gauss(int equ, int var){//equ为方程数,var为未知数个数
int i, j, k;
int max_r;//当前列绝对值最大的行
int col;//当前处理的列
int ta, tb;
int LCM;
int temp;
int free_x_num;
int free_index;
for(int i = ; i <= var; i++){
x[i] = ;
free_x[i] = true;//初始化全部为变元
}
for(k = , col = ; k < equ && col < var; k++, col++){
//枚举当前处理的行k
//找到当前col列元素绝对值最大的行与第k行交换
max_r = k;
for(i = k + ; i < equ; i++){
if(abs(a[i][col] > abs(a[max_r][col]))) max_r = i;//记录当前列中最大值所在行
}
if(max_r != k){//与第k行交换
for(int j = k; j < var + ; j++){
swap(a[k][j], a[max_r][j]);
}
}
if(a[k][col] == ){//说明col列中第k行以下全是0了,则处理当前下一行
k--;
continue;
}
for(i = k + ; i < equ; i++){//枚举要删去的行
if(a[i][col] != ){
LCM = lcm(abs(a[i][col]), abs(a[k][col]));
ta = LCM / abs(a[i][col]);
tb = LCM / abs(a[k][col]);
if(a[i][col] * a[k][col] < ) tb = -tb;
for(j = col; j < var + ; j++){
a[i][j] = ((a[i][j] * ta - a[k][j] * tb) % mod + mod) % mod;
}
}
}
}
//无解的情况,化简的增广矩阵中存在(0,0,...1)这样的行(a!=0)
for(i = k; i < equ; i++){
if(a[i][col] != ) return -;
}
//无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.
//且出现的行数即为*变元的个数.
if(k < var){
for(i = k - ; i >= ; i--){
// 第i行一定不会是(0, 0, ..., 0)的情况,因为这样的行是在第k行到第equ行.
// 同样,第i行一定不会是(0, 0, ..., a), a != 0的情况,这样的无解的.
free_x_num = ;//用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元.
for(j = ; j < var; j++){
if(a[i][j] && free_x[j]) free_x_num++, free_index = j;
}
if(free_x_num > ) continue;//无法求解出确定的变元
// 说明就只有一个不确定的变元free_index,那么可以求解出该变元,且该变元是确定的
temp = a[i][var];
for(j = ; j < var; j++){
if(a[i][j] != && j != free_index) temp -= a[i][j] * x[j] % mod;
temp = (temp % mod + mod) % mod;
}
x[free_index] = (temp / a[i][free_index]) % mod;//求出该变元
free_x[free_index] = ;//该变元已经确定,取消对应变元标记
}
return var - k;//*变元有var-k个
}
//唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵.
//计算出Xn-1, Xn-2 ... X0.
for(i = var - ; i >= ; i--){
temp = a[i][var];
for(j = i + ; j < var; j++){
if(a[i][j] != ) temp -= a[i][j] * x[j];
temp = (temp % mod + mod) % mod;
}
while(temp % a[i][i] != ) temp += mod;
x[i] = (temp /a[i][i]) % mod;
}
return ;
} int tran(char *s){
if(strcmp(s, "MON") == ) return ;
if(strcmp(s, "TUE") == ) return ;
if(strcmp(s, "WED") == ) return ;
if(strcmp(s, "THU") == ) return ;
if(strcmp(s, "FRI") == ) return ;
if(strcmp(s, "SAT") == ) return ;
return ;
} char s1[], s2[]; int main(void){
int n, m, k, t;
while(~scanf("%d%d", &n, &m)){
if(n + m == ) break;
memset(a, , sizeof(a));
for(int i = ; i < m; i++){
scanf("%d%s%s", &k, s1, s2);
a[i][n] = ((tran(s2) - tran(s1) + ) % mod + mod) % mod;//方程组的常数项
while(k--){
scanf("%d", &t);
t--;
a[i][t]++;
if(a[i][t] >= mod) a[i][t] %= mod;
}
}
int cnt = Gauss(m, n);//m为条件数目即方程数
if(cnt == ){
for(int i = ; i < n; i++){
if(x[i] <= ) x[i] += ;//题意要求每件物品最少生产3天,最多生产9天
printf("%d ", x[i]);
}
puts("");
}else if(cnt == -) puts("Inconsistent data.");
else puts("Multiple solutions.");
}
return ;
}
上一篇:HDU 5833 Zhu and 772002(高斯消元)


下一篇:[置顶] hdu 4418 高斯消元解方程求期望