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

来源:互联网 发布:网络语言bug什么意思 编辑:程序博客网 时间:2024/06/05 04:19


Widget Factory
Time Limit: 7000MS Memory Limit: 65536KTotal 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 build a widget depends on its type: the simple widgets need only 3 days, but the most complex ones may need as many as 9 days. 

The factory is currently in a state of complete chaos: recently, the factory has been bought by a new owner, and the new director has fired almost everyone. The new staff know almost nothing about building widgets, and it seems that no one remembers how many days are required to build each diofferent type of widget. This is very embarrassing when a client orders widgets and the factory cannot tell the client how many days are needed to produce the required goods. Fortunately, there are records that say for each widgeteer the date when he started working at the factory, the date when he was fired and what types of widgets he built. The problem is that the record does not say the exact date of starting and leaving the job, only the day of the week. Nevertheless, even this information might be helpful in certain cases: for example, if a widgeteer started working on a Tuesday, built a Type 41 widget, and was fired on a Friday,then we know that it takes 4 days to build a Type 41 widget. Your task is to figure out from these records (if possible) the number of days that are required to build the different types of widgets. 

Input

The input contains several blocks of test cases. Each case begins with a line containing two integers: the number 1 ≤ n ≤ 300 of the different types, and the number 1 ≤ m ≤ 300 of the records. This line is followed by a description of the m records. Each record is described by two lines. The first line contains the total number 1 ≤ k ≤ 10000 of widgets built by this widgeteer, followed by the day of week when he/she started working and the day of the week he/she was fired. The days of the week are given bythe strings `MON', `TUE', `WED', `THU', `FRI', `SAT' and `SUN'. The second line contains k integers separated by spaces. These numbers are between 1 and n , and they describe the diofferent types of widgets that the widgeteer built. For example, the following two lines mean that the widgeteer started working on a Wednesday, built a Type 13 widget, a Type 18 widget, a Type 1 widget, again a Type 13 widget,and was fired on a Sunday. 

4 WED SUN 
13 18 1 13 

Note that the widgeteers work 7 days a week, and they were working on every day between their first and last day at the factory (if you like weekends and holidays, then do not become a widgeteer!). 

The input is terminated by a test case with n = m = 0 .

Output

For each test case, you have to output a single line containing n integers separated by spaces: the number of days required to build the different types of widgets. There should be no space before the first number or after the last number, and there should be exactly one space between two numbers. If there is more than one possible solution for the problem, then write `Multiple solutions.' (without the quotes). If you are sure that there is no solution consistent with the input, then write `Inconsistent data.'(without the quotes).

Sample Input

2 32 MON THU1 23 MON FRI1 1 23 MON SUN1 2 210 21 MON TUE 31 MON WED30 0

Sample Output

8 3Inconsistent data.

Hint

Huge input file, 'scanf' recommended to avoid TLE. 

Source

Central Europe 2005
解题思路:

被这个题意弄得真的无语了,读了N遍.......

公司被吞并,老员工几乎全部被炒鱿鱼。一共有n种不同的工具,编号1-N(代码中是0—N-1),每种工具的加工时间为3—9天,但是现在老员工不在我们不知道每种工具的加工时间,庆幸的是还保留着一些对工人制造工具的记录,对于每个老员工,他的记录包括,他开始工作的时间(在某个星期的星期几),被炒鱿鱼的时间(某个星期的星期几),在第几个星期不知道.....在这段时间里,他正好加工了k件物品,给出了这k件物品的编号。我们要做的就是通过这些记录,来确定每种工具的加工时间是多少。

思路为建立线性方程组(涉及到了取模):

对于每个记录,建立一个方程,所有的记录,建立为如下的方程:

(a[0][0]*X0 + a[0][1] *X1 + a[0][2]*X2+...........a[0][n-1]*Xn-1 )  %7=  a[0][n] 

(a[1][0]*X0 + a[1][1] *X1 + a[1][2]*X2+...........a[1][n-1]*Xn-1 )  %7=  a[1][n] 

................................................................................................................................

(a[m-1][0]*X0 + a[m-1][1] *X1 + a[m-1][2]*X2+...........a[m-1][n-1]*Xn-1 )  %7=  a[m-1][n] 

如上方程组,表示的是一共有m个记录,即有m个方程,有n个变量(表示n个物品,编号0-N-1),方程中的x0, x1, x2........xn-1,代表的是第i种工具加工需要多长时间

a[ i ] [ j ]  (0<=j<=n-1) ,表示第i个方程中(i从0开始),编号为j的物品,加工的个数,即Xj,  a[i][n] ,表示第i个方程中,加工完所有种类的工具,需要的时间,因为不知道开始时间和结束时间是在第几个星期,只知道星期几,所以有 %7.

以样例中的例子,来说一下方程组的建立.

2 32 MON THU1 23 MON FRI1 1 23 MON SUN1 2 2
初始化,增广矩阵a[][]初始化为0.

样例中 2 3 代表 有一共两种工具(编号0,1), 3个工人的记录。

第一个工人的记录为 2 表示他加工了两个工具,开始时间是 MON,表示星期一,结束时间为THU,表示星期四,下一行的1,2表示,他加工两个工具,这两个工具的编号,1,2(代码中是 0,1)

这样建立的方程为   (1* X0+ 1 *X2 )%7= ((4-1)%7+7)%7 ,方程后边得是正整数.

第二个工人的记录为3 表示他加工了三个工具,开始时间为 MON,表示星期一,结束时间为FRI,表示星期五,下一行的1,1,2表示,他加工的三个工具里面,编号分别是1,1,2,也就是第一种工具加工了两个,第二种工具加工了1个。

这样建立的方程为  (2*X0+1*X2)%7=((5-1)%7+7)%7, 

依次类推,

第三个工人的记录建立的方程为  (1*X0+2*X2) %7 =((7-1)%7+7)%7.

我们要做的就是根据这三个方程,把x0,x1,解出来。

当没有解时,输出  Inconsistent data. 无穷解时 输出 Multiple solutions. ,否则输出每种工具的加工时间...

这种题目需要把模板修改一下...一上午就研究了个模板是怎么回事....

代码:

#include <iostream>#include <string.h>#include <stdio.h>#include <cmath>using namespace std;const int maxn = 310;int equ, var; // 有equ个方程,var个变元。增广阵行数为equ, 分别为0到equ - 1,列数为var + 1,分别为0到var.int a[maxn][maxn];//增广矩阵int x[maxn]; // 解集.int free_num;inline int gcd(int a, int b){    int t;    while(b!=0)    {        t=b;        b=a%b;        a=t;    }    return a;}inline int lcm(int a, int b){    return a*b/gcd(a,b);}// 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,但无整数解,-1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数)int change(char s[]){    if(strcmp(s,"MON")==0) return 1;    else if(strcmp(s,"TUE")==0) return 2;    else if(strcmp(s,"WED")==0) return 3;    else if(strcmp(s,"THU")==0) return 4;    else if(strcmp(s,"FRI")==0) return 5;    else if(strcmp(s,"SAT")==0) return 6;    else  return 7;}int Gauss(void){    int i,j,k;    int max_r; // 当前这列绝对值最大的行.    int col; // 当前处理的列.    int ta, tb;    int LCM;    int temp;    // 转换为阶梯阵.    col = 0; // 当前处理的列.    for (k = 0; k < equ && col < var; k++, col++)    { // 枚举当前处理的行.        // 找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差)        max_r = k;        for (i = k + 1; i < equ; i++)        {            if (abs(a[i][col]) > abs(a[max_r][col])) max_r = i;        }        if (max_r != k)        { // 与第k行交换.            for (j = k; j < var + 1; j++) swap(a[k][j], a[max_r][j]);        }        if (a[k][col] == 0)        { // 说明该col列第k行以下全是0了,则处理当前行的下一列.            k--;            continue;        }        for (i = k + 1; i < equ; i++)        { // 枚举要删去的行.            if (a[i][col] != 0)            {                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] < 0) tb = -tb; // 异号的情况是两个数相加.                for (j = col; j < var + 1; j++)                {                    a[i][j] =(((a[i][j] * ta - a[k][j] * tb)%7+7)%7);                }            }        }    }    //Debug();    // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).    for (i = k; i < equ; i++)    { // 对于无穷解来说,如果要判断哪些是自由变元,那么初等行变换中的交换就会影响,则要记录交换.        if (a[i][col] != 0) return -1;    }    // 2. 无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.    // 且出现的行数即为自由变元的个数.    if (k < var)        return var - k; // 自由变元有var - k个.    // 3. 唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵.    // 计算出Xn-1, Xn-2 ... X0.    for (i = var - 1; i >= 0; i--)    {        temp = a[i][var];//等式右边的数        for (j = i + 1; j < var; j++)        {            if (a[i][j] != 0) temp -= a[i][j] * x[j];//把已知的解带入,减去,只剩下,一个未知的解            temp=(temp%7+7)%7;        }        while(temp%a[i][i]!=0)//外层每次循环都是为了求 a[i][i],因为它是每个方程中唯一一个未知的变量(求该方程时)            temp+=7;//因为天数不确定,而a[i][i]必须得为整数才可以,周期为7        x[i]=(temp/a[i][i])%7;    }    return 0;}int main(void){    int n,m,k,num;    char s[5],e[5];    while(scanf("%d%d",&n,&m)!=EOF&&(n||m))    {        memset(a,0,sizeof(a));        for(int i=0;i<m;i++)        {            scanf("%d",&k);            scanf("%s%s",s,e);            a[i][n]=((change(e)-change(s)+1)%7+7)%7;            for(int j=1;j<=k;j++)//k是他打造的数量            {                scanf("%d",&num);//可能是相同的数                num--;                a[i][num]++;//系数++                a[i][num]%=7;//有重复的。            }        }        equ=m;//有m个方程        var=n;//有多少个变量        free_num = Gauss();        if(free_num==0)        {            for(int i=0;i<n;i++)//根据题意,每个零件的加工时间在3-9天.                if(x[i]<=2)                x[i]+=7;            for(int i=0;i<n-1;i++)             cout<<x[i]<<" ";            cout<<x[n-1]<<endl;        }        else if(free_num==-1)            cout<<"Inconsistent data."<<endl;        else            cout<<"Multiple solutions."<<endl;    }    return 0;}

参考:http://blog.csdn.net/duanxian0621/article/details/7408887



高斯消元法,是线性代数中的一个算法,可用来求解线性方程组,并可以求出矩阵的秩,以及求出可逆方阵的逆矩阵。
高斯消元法的原理是:
若用初等行变换将增广矩阵 化为 ,则AX = B与CX = D是同解方程组。
所以我们可以用初等行变换把增广矩阵转换为行阶梯阵,然后回代求出方程的解。

以上是线性代数课的回顾,下面来说说高斯消元法在编程中的应用。

首先,先介绍程序中高斯消元法的步骤:
(我们设方程组中方程的个数为equ,变元的个数为var,注意:一般情况下是n个方程,n个变元,但是有些题目就故意让方程数与变元数不同)

1. 把方程组转换成增广矩阵。

2. 利用初等行变换来把增广矩阵转换成行阶梯阵。
枚举k从0到equ – 1,当前处理的列为col(初始为0) ,每次找第k行以下(包括第k行),col列中元素绝对值最大的列与第k行交换。如果col列中的元素全为0,那么则处理col + 1列,k不变。

3. 转换为行阶梯阵,判断解的情况。

① 无解
当方程中出现(0, 0, …, 0, a)的形式,且a != 0时,说明是无解的。

② 唯一解
条件是k = equ,即行阶梯阵形成了严格的上三角阵。利用回代逐一求出解集。

③ 无穷解。
条件是k < equ,即不能形成严格的上三角形,自由变元的个数即为equ – k,但有些题目要求判断哪些变元是不缺定的。
    这里单独介绍下这种解法:
首先,自由变元有var - k个,即不确定的变元至少有var - k个。我们先把所有的变元视为不确定的。在每个方程中判断不确定变元的个数,如果大于1个,则该方程无法求解。如果只有1个变元,那么该变元即可求出,即为确定变元。

以上介绍的是求解整数线性方程组的求法,复杂度是O(n3)。浮点数线性方程组的求法类似,但是要在判断是否为0时,加入EPS,以消除精度问题。


下面讲解几道OJ上的高斯消元法求解线性方程组的题目:

POJ 1222 EXTENDED LIGHTS OUT
http://acm.pku.edu.cn/JudgeOnline/problem?id=1222
POJ 1681 Painter's Problem
http://acm.pku.edu.cn/JudgeOnline/problem?id=1681
POJ 1753 Flip Game
http://acm.pku.edu.cn/JudgeOnline/problem?id=1753
POJ 1830 开关问题
http://acm.pku.edu.cn/JudgeOnline/problem?id=1830

POJ 3185 The Water Bowls

http://acm.pku.edu.cn/JudgeOnline/problem?id=3185
开关窗户,开关灯问题,很典型的求解线性方程组的问题。方程数和变量数均为行数*列数,直接套模板求解即可。但是,当出现无穷解时,需要枚举解的情况,因为无法判断哪种解是题目要求最优的。

POJ 2947 Widget Factory
http://acm.pku.edu.cn/JudgeOnline/problem?id=2947
求解同余方程组问题。与一般求解线性方程组的问题类似,只要在求解过程中加入取余即可。
注意:当方程组唯一解时,求解过程中要保证解在[3, 9]之间。

POJ 1166 The Clocks
http://acm.pku.edu.cn/JudgeOnline/problem?id=1166
经典的BFS问题,有各种解法,也可以用逆矩阵进行矩阵相乘。
但是这道题用高斯消元法解决好像有些问题(困扰了我N天...持续困扰中...),由于周期4不是素数,故在求解过程中不能进行取余(因为取余可能导致解集变大),但最后求解集时,还是需要进行取余操作,那么就不能保证最后求出的解是正确的...在discuss里提问了好几天也没人回答...希望哪位路过的大牛指点下~~

POJ 2065 SETI
http://acm.pku.edu.cn/JudgeOnline/problem?id=2065
同样是求解同余方程组问题,由于题目中的p是素数,可以直接在求解时取余,套用模板求解即可。(虽然AC的人很少,但它还是比较水的一道题,)

POJ 1487 Single-Player Games
http://acm.pku.edu.cn/JudgeOnline/problem?id=1487
很麻烦的一道题目...题目中的叙述貌似用到了编译原理中的词法定义(看了就给人不想做的感觉...)
解方程组的思想还是很好看出来了(前提是通读题目不下5遍...),但如果把树的字符串表达式转换成方程组是个难点,我是用栈 + 递归的做法分解的。首先用栈的思想求出该结点的孩子数,然后递归分别求解各个孩子。
这题解方程组也与众不同...首先是求解浮点数方程组,要注意精度问题,然后又询问不确定的变元,按前面说的方法求解。
一顿折腾后,这题居然写了6000+B...而且囧的是巨人C++ WA,G++ AC,可能还是精度的问题吧...看这题目,看这代码,就没有改的欲望...

hdu OJ 2449
http://acm.hdu.edu.cn/showproblem.php?pid=2449
哈尔滨现场赛的一道纯高斯题,当时鹤牛敲了1个多小时...主要就是写一个分数类,套个高精模板(偷懒点就Java...)搞定~~
注意下0和负数时的输出即可。

fze OJ 1704
http://acm.fzu.edu.cn/problem.php?pid=1704
福大月赛的一道题目,还是经典的开关问题,但是方程数和变元数不同(考验模板的时候到了~~),最后要求增广阵的阶,要用到高精度~~

Sgu 275 To xor or not to xor
http://acm.sgu.ru/problem.php?contest=0&problem=275
题解:
http://hi.baidu.com/czyuan%5Facm/blog/item/be3403d32549633d970a16ee.html


模板:

//高斯消元模板#include <iostream>#include <stdio.h>#include <string.h>#include <string>#include <cmath>using namespace std;const int maxn=105;int equ,var; // 有equ个方程,var个变元。增广阵行数为equ, 分别为0到equ - 1,列数为var + 1,分别为0到var.int a[maxn][maxn];int x[maxn]; // 解集.bool free_x[maxn]; // 判断是否是不确定的变元.int free_num;void Debug(void){    int i,j;    for(i=0;i<equ;i++)    {        for(j=0;j<var+1;j++)        {            cout<<a[i][j]<<" ";        }        cout<<endl;    }    cout<<endl;}inline int gcd(int a, int b){    int t;    while (b!=0)    {        t=b;        b=a%b;        a=t;    }    return a;}inline int lcm(int a, int b){    return a*b/gcd(a,b);}// 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,但无整数解,-1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数)int Gauss(void){    int i,j,k;    int max_r; // 当前这列绝对值最大的行.    int col; // 当前处理的列.    int ta,tb;    int LCM;    int temp;    int free_x_num;    int free_index;    // 转换为阶梯阵.    col=0; // 当前处理的列.    for(k=0;k<equ&&col<var;k++,col++)    { // 枚举当前处理的行.        // 找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差)        max_r=k;        for(i=k+1;i<equ;i++)        {            if(abs(a[i][col])>abs(a[max_r][col]))                max_r=i;        }        if(max_r!=k)        { // 与第k行交换.            for(j=k;j<var+1;j++)                swap(a[k][j],a[max_r][j]);        }        if(a[k][col]==0)        { // 说明该col列第k行以下全是0了,则处理当前行的下一列.            k--; continue;        }        for(i=k+1;i<equ;i++)        { // 枚举要删去的行.            if (a[i][col]!=0)            {                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]<0) tb=-tb; // 异号的情况是两个数相加.                for(j=col;j<var+1;j++)                {                    a[i][j]=a[i][j]*ta-a[k][j]*tb;                }            }        }    }    //Debug();    // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).    for(i=k;i<equ;i++)    { // 对于无穷解来说,如果要判断哪些是自由变元,那么初等行变换中的交换就会影响,则要记录交换.        if (a[i][col]!=0)            return -1;    }    // 2. 无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.    // 且出现的行数即为自由变元的个数.    if(k<var)    {        // 首先,自由变元有var - k个,即不确定的变元至少有var - k个.        for (i=k-1;i>=0;i--)        {            // 第i行一定不会是(0, 0, ..., 0)的情况,因为这样的行是在第k行到第equ行.            // 同样,第i行一定不会是(0, 0, ..., a), a != 0的情况,这样的无解的.            free_x_num=0; // 用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元.            for(j=0;j<var;j++)            {                if(a[i][j]!=0&&free_x[j])                    free_x_num++,free_index = j;            }            if(free_x_num>1)                continue; // 无法求解出确定的变元.            // 说明就只有一个不确定的变元free_index,那么可以求解出该变元,且该变元是确定的.            temp=a[i][var];            for(j=0;j<var;j++)            {                if(a[i][j]!=0&&j!=free_index)                temp-=a[i][j]*x[j];            }            x[free_index]=temp/a[i][free_index]; // 求出该变元.            free_x[free_index]=0; // 该变元是确定的.        }        return var-k; // 自由变元有var - k个.    }    // 3. 唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵.    // 计算出Xn-1, Xn-2 ... X0.    for (i=var-1;i>=0;i--)    {        temp=a[i][var];        for(j=i+1;j<var;j++)        {            if(a[i][j]!=0)                 temp-=a[i][j]*x[j];        }        if(temp%a[i][i]!=0)             return -2; // 说明有浮点数解,但无整数解.        x[i]=temp/a[i][i];    }    return 0;}int main(void){    int i, j;    while (scanf("%d %d",&equ,&var)!=EOF)    {        memset(a,0,sizeof(a));        memset(x,0,sizeof(x));        memset(free_x,1,sizeof(free_x)); // 一开始全是不确定的变元                for(i=0;i<equ;i++)//构造增广矩阵            for(j=0;j<var+1;j++)                scanf("%d",&a[i][j]);//        Debug();        free_num=Gauss();        if(free_num==-1) printf("无解!\n");        else if(free_num==-2) printf("有浮点数解,无整数解!\n");        else if(free_num>0)        {            printf("无穷多解! 自由变元个数为%d\n",free_num);            for(i=0;i<var;i++)            {                if(free_x[i]) printf("x%d 是不确定的\n",i+1);                else printf("x%d: %d\n",i+1,x[i]);            }        }        else        {            for(i=0;i<var;i++)                printf("x%d: %d\n",i+1,x[i]);        }        printf("\n");    }    return 0;}



高斯消元法,是线性代数中的一个算法,可用来求解线性方程组,并可以求出矩阵的秩,以及求出可逆方阵的逆矩阵。
高斯消元法的原理是:
若用初等行变换将增广矩阵 化为 ,则AX = B与CX = D是同解方程组。
所以我们可以用初等行变换把增广矩阵转换为行阶梯阵,然后回代求出方程的解。

以上是线性代数课的回顾,下面来说说高斯消元法在编程中的应用。

首先,先介绍程序中高斯消元法的步骤:
(我们设方程组中方程的个数为equ,变元的个数为var,注意:一般情况下是n个方程,n个变元,但是有些题目就故意让方程数与变元数不同)

1. 把方程组转换成增广矩阵。

2. 利用初等行变换来把增广矩阵转换成行阶梯阵。
枚举k从0到equ – 1,当前处理的列为col(初始为0) ,每次找第k行以下(包括第k行),col列中元素绝对值最大的列与第k行交换。如果col列中的元素全为0,那么则处理col + 1列,k不变。

3. 转换为行阶梯阵,判断解的情况。

① 无解
当方程中出现(0, 0, …, 0, a)的形式,且a != 0时,说明是无解的。

② 唯一解
条件是k = equ,即行阶梯阵形成了严格的上三角阵。利用回代逐一求出解集。

③ 无穷解。
条件是k < equ,即不能形成严格的上三角形,自由变元的个数即为equ – k,但有些题目要求判断哪些变元是不缺定的。
    这里单独介绍下这种解法:
首先,自由变元有var - k个,即不确定的变元至少有var - k个。我们先把所有的变元视为不确定的。在每个方程中判断不确定变元的个数,如果大于1个,则该方程无法求解。如果只有1个变元,那么该变元即可求出,即为确定变元。

以上介绍的是求解整数线性方程组的求法,复杂度是O(n3)。浮点数线性方程组的求法类似,但是要在判断是否为0时,加入EPS,以消除精度问题。


下面讲解几道OJ上的高斯消元法求解线性方程组的题目:

POJ 1222 EXTENDED LIGHTS OUT
http://acm.pku.edu.cn/JudgeOnline/problem?id=1222
POJ 1681 Painter's Problem
http://acm.pku.edu.cn/JudgeOnline/problem?id=1681
POJ 1753 Flip Game
http://acm.pku.edu.cn/JudgeOnline/problem?id=1753
POJ 1830 开关问题
http://acm.pku.edu.cn/JudgeOnline/problem?id=1830

POJ 3185 The Water Bowls

http://acm.pku.edu.cn/JudgeOnline/problem?id=3185
开关窗户,开关灯问题,很典型的求解线性方程组的问题。方程数和变量数均为行数*列数,直接套模板求解即可。但是,当出现无穷解时,需要枚举解的情况,因为无法判断哪种解是题目要求最优的。

POJ 2947 Widget Factory
http://acm.pku.edu.cn/JudgeOnline/problem?id=2947
求解同余方程组问题。与一般求解线性方程组的问题类似,只要在求解过程中加入取余即可。
注意:当方程组唯一解时,求解过程中要保证解在[3, 9]之间。

POJ 1166 The Clocks
http://acm.pku.edu.cn/JudgeOnline/problem?id=1166
经典的BFS问题,有各种解法,也可以用逆矩阵进行矩阵相乘。
但是这道题用高斯消元法解决好像有些问题(困扰了我N天...持续困扰中...),由于周期4不是素数,故在求解过程中不能进行取余(因为取余可能导致解集变大),但最后求解集时,还是需要进行取余操作,那么就不能保证最后求出的解是正确的...在discuss里提问了好几天也没人回答...希望哪位路过的大牛指点下~~

POJ 2065 SETI
http://acm.pku.edu.cn/JudgeOnline/problem?id=2065
同样是求解同余方程组问题,由于题目中的p是素数,可以直接在求解时取余,套用模板求解即可。(虽然AC的人很少,但它还是比较水的一道题,)

POJ 1487 Single-Player Games
http://acm.pku.edu.cn/JudgeOnline/problem?id=1487
很麻烦的一道题目...题目中的叙述貌似用到了编译原理中的词法定义(看了就给人不想做的感觉...)
解方程组的思想还是很好看出来了(前提是通读题目不下5遍...),但如果把树的字符串表达式转换成方程组是个难点,我是用栈 + 递归的做法分解的。首先用栈的思想求出该结点的孩子数,然后递归分别求解各个孩子。
这题解方程组也与众不同...首先是求解浮点数方程组,要注意精度问题,然后又询问不确定的变元,按前面说的方法求解。
一顿折腾后,这题居然写了6000+B...而且囧的是巨人C++ WA,G++ AC,可能还是精度的问题吧...看这题目,看这代码,就没有改的欲望...

hdu OJ 2449
http://acm.hdu.edu.cn/showproblem.php?pid=2449
哈尔滨现场赛的一道纯高斯题,当时鹤牛敲了1个多小时...主要就是写一个分数类,套个高精模板(偷懒点就Java...)搞定~~
注意下0和负数时的输出即可。

fze OJ 1704
http://acm.fzu.edu.cn/problem.php?pid=1704
福大月赛的一道题目,还是经典的开关问题,但是方程数和变元数不同(考验模板的时候到了~~),最后要求增广阵的阶,要用到高精度~~

Sgu 275 To xor or not to xor
http://acm.sgu.ru/problem.php?contest=0&problem=275
题解:
http://hi.baidu.com/czyuan%5Facm/blog/item/be3403d32549633d970a16ee.html

0 0
原创粉丝点击