POJ 2497 Widget Factory [高斯消元解同余方程组]

  为了做份高斯消元的模版做了这一题,模版来自http://www.cnblogs.com/kuangbin/archive/2012/08/31/2666144.html。 但这份模版中求自由元的部分应该是错误的,从下向上枚举肯定是不对的,比如x+y+z=10,y+z=5,这个方程组中x实际上是确定的,但这份模版会将x识别为不确定元素。

  其实本来是想找份要求自由元的题目的,但还没找到。这题是求同余方程组,跟一般的高斯消元差不多,只是要在消元过程中注意模的问题,另外最后答案要通过扩展欧几里德求出。

  继续去找要求求自由元的题目。。

  

 1 #include <string.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <algorithm>
 5 #define MAXN 320
 6 #define MOD 7
 7 int n,m,k,tu;
 8 char day[][6]={"MON","TUE","WED","THU","FRI","SAT","SUN"},s1[5],s2[5];
 9 int getday(char *s){
10     for(int i=0;i<7;i++)if(strcmp(day[i],s)==0)return i;
11     return -1;
12 }
13 //高斯消元解同余线性方程组
14 int x[MAXN][MAXN],ans[MAXN],fre[MAXN];
15 void exgcd(int a,int b,int &x,int &y){
16     b?(exgcd(b,a%b,y,x),y-=x*(a/b)):(x=1,y=0);
17 }
18 int gcd(int a,int b){
19     return b==0?a:gcd(b,a%b);
20 }
21 inline int lcm(int x,int y){
22     return x*y/gcd(x,y);
23 }
24 int gauss(int n,int m){//n行m+1列,方程从0,0~n-1,m-1,第m列是常数
25     memset(ans,0,sizeof ans);
26     memset(fre,0,sizeof fre);
27     int row=0,col=0;
28     for(;row<n&&col<m;col++){
29         //保证当前行的元素是最大的
30         int maxr=row;
31         for(int i=row+1;i<n;i++)if(abs(x[i][col])>abs(x[maxr][col]))maxr=i;
32         if(maxr!=row)for(int i=0;i<=m;i++)std::swap(x[maxr][i],x[row][i]);
33         if(x[row][col]==0)continue;
34         //将下面全部变为0
35         for(int i=row+1;i<n;i++)
36          if(x[i][col]!=0){
37             int g=lcm(abs(x[row][col]),abs(x[i][col])),ga=g/x[row][col],gb=g/x[i][col];
38             if(x[i][col]*x[row][col]<0)ga=-ga;
39             for(int j=col;j<=m;j++){
40                 x[i][j]=(x[i][j]*gb-x[row][j]*ga)%MOD;
41                 if(x[i][j]<0)x[i][j]+=MOD;
42             }
43          }
44          row++;
45     }
46     //判断无解(0,0....a)
47     for(int i=row;i<n;i++)if(x[i][m]!=0)return -1;
48     //判断无穷多解,有效方程个数小于未知数数量
49     if(row<m){
50         return m-row;
51     }
52     //求唯一解
53     for(int i=m-1;i>=0;i--){
54         int tmp=0,tx,ty;
55         for(int j=i+1;j<m;j++)tmp+=ans[j]*x[i][j],tmp%=MOD;
56         tmp=(x[i][m]-tmp)%MOD;
57         if(tmp<MOD)tmp+=MOD;
58         //用扩展欧几里德求解
59         exgcd(x[i][i],MOD,tx,ty),tx%=MOD;
60         ans[i]=tx*tmp/gcd(x[i][i],MOD);
61     }
62     return 0;
63 }
64 
65 int main(){
66     freopen("test.in","r",stdin);
67     while(scanf("%d%d",&n,&m),n||m){
68         memset(x,0,sizeof x);
69         for(int i=0;i<m;i++){
70             scanf("%d%s%s",&k,s1,s2);
71             while(k--){
72                 scanf("%d",&tu),x[i][tu-1]++,x[i][tu-1]%=MOD;
73             }
74             x[i][n]=((getday(s2)-getday(s1)+1)%MOD+MOD)%MOD;
75         }
76         int t=gauss(m,n);
77         if(t==-1)printf("Inconsistent data.\n");
78         else if(t>0)printf("Multiple solutions.\n");
79         else if(t==0){
80             for(int i=0;i<n;i++){
81                 ans[i]=(ans[i]%MOD+MOD)%MOD;
82                 if(ans[i]<3)ans[i]+=7;
83                 printf("%d%c",ans[i],i==n-1?'\n':' ');
84             }
85         }
86     }
87     return 0;
88 }
posted @ 2012-09-02 17:48  Burn_E  阅读(264)  评论(0编辑  收藏  举报