zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    C++学习9 this指针详解
    福建省第八届 Triangles
    UVA 11584 Partitioning by Palindromes
    POJ 2752 Seek the Name, Seek the Fame
    UVA 11437 Triangle Fun
    UVA 11488 Hyper Prefix Sets (字典树)
    HDU 2988 Dark roads(kruskal模板题)
    HDU 1385 Minimum Transport Cost
    HDU 2112 HDU Today
    HDU 1548 A strange lift(最短路&&bfs)
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/7581875.html
Copyright © 2011-2022 走看看