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  则相当于6 * X2 + 7 * Y = 4,利用扩展gcd则可求出X2为3,则第一个方程为

X1 * 1 % 7 + 1*3 % 7 = 4 % 7 则相当于 X1 + 7 * Y = 1  得到X1=1。

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <set>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const double pi= acos(-1.0);
const double esp=1e-6;
const int MAXN=310;
int aug[MAXN][MAXN];<span style="background-color: rgb(255, 255, 255);">//增广矩阵行数为m,分别为0到m-1,列数为n+1,分别为0到n.</span>
int x[MAXN];//解集
int free_num;
int m,n;//m个方程。n个变元
int gcd(int a,int b) {
    int r;
    while(b!=0) {
        r=b;
        b=a%b;
        a=r;
    }
    return a;
}
int lcm(int a,int b) {
    return a/gcd(a,b)*b;
}
/*void Debug(void)
{
    puts("");
    int i,j;
    for(i=0;i<m;i++){
        for(j=0;j<n+1;j++){
            cout << matrix[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}*/
int trans(char *str) {
    if(strcmp(str,"MON")==0) return 1;
    else if(strcmp(str,"TUE")==0) return 2;
    else if(strcmp(str,"WED")==0) return 3;
    else if(strcmp(str,"THU")==0) return 4;
    else if(strcmp(str,"FRI")==0) return 5;
    else if(strcmp(str,"SAT")==0) return 6;
    else if(strcmp(str,"SUN")==0) return 7;
}
// 高斯消元法解方程组(Gauss-Jordan elimination).(-1表示无解。
//0表示唯一解。大于0表示无穷解。并返回自由变元的个数)
int Gauss() {
    int i,j;
    int row,col,max_r;// 当前这列绝对值最大的行;
    int LCM;
    int ta,tb;
    int tmp;
    for(row=0,col=0; row<m&&col<n; row++,col++) {
        // 枚举当前处理的行.
        // 找到该col列元素绝对值最大的那行与第row行交换.(为了在除法时减小误差)
        max_r=row;
        for(i=row+1; i<m; i++) {
            if(abs(aug[i][col])>abs(aug[max_r][col]))
                max_r=i;
        }
        if(max_r!=row) {
            // 与第row行交换
            for(j=row; j<n+1; j++)
                swap(aug[row][j],aug[max_r][j]);
        }
        if(aug[row][col]==0) {
            // 说明该col列第row行下面全是0了,则处理当前行的下一列.
            row--;
            continue;
        }
        for(i=row+1; i<m; i++) {
            // 枚举要删去的行.
            if(aug[i][col]!=0) {
                LCM=lcm(abs(aug[i][col]),abs(aug[row][col]));
                ta=LCM/abs(aug[i][col]);
                tb=LCM/abs(aug[row][col]);
                if(aug[i][col]*aug[row][col]<0) tb=-tb;//异号的情况是相加
                for(j=col; j<n+1; j++) {
                    aug[i][j]=(((aug[i][j]*ta-aug[row][j]*tb)%7+7)%7);
                }
            }
        }
    }
    //Debug();
    // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这种行(a != 0).
    for(i=row; i<m; i++) {
        if(aug[i][col]!=0)  return -1;
    }
    // 2. 无穷解的情况: 在n * (n + 1)的增广阵中出现(0, 0, ..., 0)这种行,即说明没有形成严格的上三角阵.
    // 且出现的行数即为自由变元的个数.
    if(row<n){
        return n-row;
    }
     // 3. 唯一解的情况: 在n * (n + 1)的增广阵中形成严格的上三角阵.
    // 计算出Xn-1, Xn-2 ... X0.
    for(i=n-1; i>=0; i--) {
        tmp=aug[i][n];//等式右边的数
        for(j=i+1; j<n; j++) {
            if(aug[i][j]!=0) tmp-=aug[i][j]*x[j];//把已知的解带入。减去,仅仅剩下,一个未知的解
            tmp=(tmp%7+7)%7;
        }
        while(tmp%aug[i][i]!=0)//外层每次循环都是为了求 a[i][i],由于它是每一个方程中唯一一个未知的变量(求该方程时)
            tmp+=7;//由于天数不确定,而aug[i][i]必须得为整数才干够,周期为7
        x[i]=(tmp/aug[i][i])%7;
    }
    return 0;
}
int main(void) {
    int nn,mm,i,j,k;
    int num;
    char Start[5],End[5];
    while(~scanf("%d %d",&nn,&mm)) {
        if(nn==0&&mm==0) break;
        n=m=0;
        memset(aug,0,sizeof(aug));
        for(i=0; i<mm; i++) {
            scanf("%d",&k);
            scanf("%s %s",Start,End);
            aug[i][nn]=((trans(End)-trans(Start)+1)%7+7)%7;
            for(j=1; j<=k; j++) {
                scanf("%d",&num);
                num--;
                aug[i][num]++;
                aug[i][num]%=7;//有反复的
            }
        }
        m=mm;
        n=nn;
        free_num = Gauss();
        if(free_num==0) {
            for(i=0; i<n; i++)
                if(x[i]<3)//依据题意,每一个零件的加工时间在3-9天.
                    x[i]+=7;
            for(i=0; i<n-1; i++)
                printf("%d ",x[i]);
            printf("%d\n",x[i]);
        } else if(free_num==-1)
            puts("Inconsistent data.");
        else
            puts("Multiple solutions.");
    }
    return 0;
}
时间: 2024-10-10 22:23:45

POJ 2947-Widget Factory(高斯消元解同余方程式)的相关文章

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

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

[ACM] POJ 2947 Widget Factory (高斯消元)

Widget Factory Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 4436   Accepted: 1502 Description The widget factory produces several different kinds of widgets. Each widget is carefully built by a skilled widgeteer. The time required to

poj 2947 Widget Factory (高斯消元,解模线性方程)

链接:poj 2947 题意:生产一些零件,已知零件种数,记录条数 记录只记录了某次生产从周几开始,周几结束,以及生产了哪些产品. 每件商品生产所需天数为3-9天. 求每样产品需要多少天才能完成. 若无解输出Inconsistent data. 有无穷解输出Multiple solutions. 有唯一解,输出其解 分析:根据题目所给信息,可以列出同余方程组,再根据高斯消元求解, 但还得判断是无解,无穷解,还是唯一解 1.系数矩阵的秩若与增广矩阵的秩不相等,则无解,否则有解 2.若有解,若增广矩

poj 2947 Widget Factory(高斯消元)

description The widget factory produces several different kinds of widgets. Each widget is carefully built by a skilled widgeteer. The time required to build a widget depends on its type: the simple widgets need only 3 days, but the most complex ones

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 天.问每种装饰物需要生产的天数.如果没有解,

uva 1564 - Widget Factory(高斯消元+逆元)

题目链接:uva 1564 - Widget Factory 题目大意:n种零件,m次工作日程,零件序号从1到n,给出m次工作日程的信息,x,s,e,表示生产了x个零件,从星期s开始到星期e(有可能是多个星期),然后给出生产的x个零件的序号.求每个零件被生产需要多少天(保证在3到10天) 解题思路:因为不能确定每个工作日程具体生产了几天,所以对应列出的方程均为线性模方程(模7),所以在高斯消元的过程中遇到除法要转换成乘上逆元. #include <cstdio> #include <cs

POJ 2065-SETI(高斯消元求解同余方程式)

题目地址:POJ 2065 题意:输入一个素数p和一个字符串s(只包含小写字母和'*'),字符串中每个字符对应一个数字,'*'对应0,'a'对应1,'b'对应2.... eg:str[] = "abc", 那么说明 n=3, 字符串所对应的数列为1, 2, 3. 同时题目定义了一个函数:a0*1^0 + a1*1^1+a2*1^2+........+an-1*1^(n-1) = f(1)(mod p), f(1) = str[0] = a = 1; a0*2^0 + a1*2^1+a2

poj 2947 Widget Factory (高斯消元解同余方程组+判断无解、多解)

http://poj.org/problem?id=2947 血泪史: CE:poj的string类型要加string库,swap不能直接交换数组 WA: x[m-1]也有可能<3啊O(≧口≦)O #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int mod=7; int n,m; char ch[

POJ 2065 SETI(高斯消元解模方程组)

题目: SETI Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 1693   Accepted: 1054 Description For some years, quite a lot of work has been put into listening to electromagnetic radio signals received from space, in order to understand what