首页 > 代码库 > [Gauss]POJ2947 Widget Factory

[Gauss]POJ2947 Widget Factory

题意: 有n种小工具要加工,每种工具的加工时间为3到9天,给了m条加工记录。

    每条记录 X s1 s2 分别代表 这个工人在s1到s2(前闭后闭)的时间里加工了X件小工具 

    下一行给出这X件小工具的种类

  要求的是每件工具的加工时间 (唯一解:输出各个时间;无解:Inconsistent data.;多个解:Multiple solutions.)

 

可以列出同余方程组:∑(ai*xi)≡T(mod 7)

          (ai是此人加工第i件物品的个数,xi是第i件物品加工所需的时间,T是此人干活的时间)

     这样列出m个同余方程 组成方程组 用高斯消元

 

比如第一个案例:

2 32 MON THU1 23 MON FRI1 1 23 MON SUN1 2 2

可以列出方程组: 1*x0+1*x1≡4(mod 7)
           2*x0+1*x1≡5(mod 7)
           1*x0+2*x1≡7(mod 7)

      1 1 4 1 1 4 1 0 1
      2 1 5 → 1 0 1 → 0 1 3
      1 2 7 0 1 3 0 0 0

即得 x0=1,x1=3
由题意 每种工具的加工时间为3到9天
故 x0=8,x1=3
解毕


下面是代码:

有mod就会有要求逆元
两种求逆元的方法

1. extend gcd
注意得到的x可能为负 要x=(x%mod+mod)%mod;
 1 void ex_gcd(int a, int b, int &x, int &y) 2 { 3     if(b) 4     { 5         ex_gcd(b, a%b, x, y); 6         int tmp=x; 7         x=y; 8         y=tmp-(a/b)*y; 9     }10     else11     {12         x=1, y=0;13         return ;14     }15 }

 

2.inverse element

注意  只适用于a<b 并且 ab互质

1 int inv(int a, int b)2 {3     return a==1? 1:inv(b%a, b)*(b-b/a)%b;4 }

 

 

此题还有一法不求逆元:

即 把被除数不断加上mod 直到它能被除数整除为止

 1 while(tmp%a[i][i]) 2      tmp+=mod; 3 x[i]=(tmp/a[i][i])%mod; 4  5 与以下等价 6  7 int xx, yy; 8 ex_gcd(a[i][i], mod, xx, yy); 9 xx=(xx%mod+mod)%mod;10 x[i]=(tmp*xx)%mod;11 12 与以下等价13 14 x[i]=(tmp*inv(a[i][i], mod))%mod;

 

完整代码:

技术分享
  1 const int mod=7;  2 int gcd(int a, int b)  3 {  4     return b==0? a:gcd(b, a%b);  5 }  6 int lcm(int a, int b)  7 {  8     return a/gcd(a, b)*b;  9 } 10 void ex_gcd(int a, int b, int &x, int &y) 11 { 12     if(b) 13     { 14         ex_gcd(b, a%b, x, y); 15         int tmp=x; 16         x=y; 17         y=tmp-(a/b)*y; 18     } 19     else 20     { 21         x=1, y=0; 22         return ; 23     } 24 } 25  26 int a[300][300];  // 增广矩阵 27 int x[300];  // 28 int free_x[300]; // 标记是否为自由未知量 29  30 int Gauss(int n, int m) // n个方程 m个未知数 即 n行m+1列 31 { 32     //转换为阶梯形式 33     int col=0, k, num=0; 34     for(k=0;k<n && col<m;k++, col++) 35     {//枚举行 36         int max_r=k; 37         for(int i=k+1;i<n;i++)//找到第col列元素绝对值最大的那行与第k行交换 38             if(abs(a[i][col])>abs(a[max_r][col])) 39                 max_r=i; 40         if(max_r!=k)// 与第k行交换 41             for(int j=col;j<m+1;j++) 42                 swap(a[k][j], a[max_r][j]); 43         if(!a[k][col])// 说明该col列第k行以下全是0了 44         { 45             k--; 46             free_x[num++]=col; 47             continue; 48         } 49         for(int i=k+1;i<n;i++)// 枚举要删除的行 50             if(a[i][col]) 51             { 52                 int LCM=lcm(abs(a[i][col]), abs(a[k][col])); 53                 int ta=LCM/abs(a[i][col]); 54                 int tb=LCM/abs(a[k][col]); 55                 if(a[i][col]*a[k][col]<0) 56                     tb=-tb; 57                 for(int j=col;j<m+1;j++) 58                     a[i][j]=((a[i][j]*ta-a[k][j]*tb)%mod+mod)%mod; 59             } 60     } 61  62     for(int i=k;i<n;i++) 63         if(a[i][col]) 64             return -1; // 无解 65  66     if(k<m)   //m-k为自由未知量个数 67         return m-k; 68  69     //  唯一解 回代 70     for(int i=m-1;i>=0;i--) 71     { 72         int tmp=a[i][m]; 73         for(int j=i+1;j<m;j++) 74         { 75             if(a[i][j]) 76                 tmp-=a[i][j]*x[j]; 77             tmp=(tmp%7+7)%7; 78         } 79         int xx, yy; 80         ex_gcd(a[i][i], mod, xx, yy); 81         xx=(xx%mod+mod)%mod; 82         x[i]=(tmp*xx)%mod; 83     } 84     return 0; 85 } 86  87  88 void init() 89 { 90     memset(a, 0, sizeof(a)); 91     memset(x, 0, sizeof(x)); 92 } 93  94 int change(char c1, char c2) 95 { 96     if(c1==M) 97         return 1; 98     if(c1==T && c2==U) 99         return 2;100     if(c1==W)101         return 3;102     if(c1==T)103         return 4;104     if(c1==F)105         return 5;106     if(c1==S && c2==A)107         return 6;108     return 7;109 }110 111 char s1[10], s2[10];112 int main()113 {114     int n, m;115     while(~scanf("%d%d", &n, &m))116     {117         if(!n && !m)118             break;119         init();120         for(int i=0;i<m;i++)121         {122             int X;123             scanf("%d%s%s", &X, s1, s2);124             a[i][n]=((change(s2[0], s2[1])-change(s1[0], s1[1])+1)%mod+mod)%mod;125             while(X--)126             {127                 int t;128                 scanf("%d", &t);129                 a[i][t-1]=(a[i][t-1]+1)%mod;130             }131         }132         int t=Gauss(m, n);133         if(t==-1)134         {135             printf("Inconsistent data.\n");136             continue;137         }138         if(t==0)139         {140             for(int i=0;i<n;i++)141                 if(x[i]<=2)142                     x[i]+=7;143             for(int i=0;i<n;i++)144             {145                 printf("%d", x[i]);146                 if(i==n-1)147                     printf("\n");148                 else149                     printf(" ");150             }151             continue;152         }153         printf("Multiple solutions.\n");154     }155     return 0;156 }
POJ 2947

 

[Gauss]POJ2947 Widget Factory