[Gauss]POJ2947 Widget Factory

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

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

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

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

可以列出同余方程组:$sumlimits_{i=0}^{n-1} a_i×x_iequiv T pmod{7}$

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

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

比如第一个案例:

2 3
2 MON THU
1 2
3 MON FRI
1 1 2
3 MON SUN
1 2 2

可以列出方程组:  

1×$x_0$+1×$x_1 equiv 4 pmod{7}$

2×$x_0$+1×$x_1 equiv 5 pmod{7}$

1×$x_0$+2×$x_1 equiv 7 pmod{7}$

[ left( egin{array}{ccc}
1 & 1 & 4 \
2 & 1 & 5 \
1 & 2 & 7 end{array} ight) o left( egin{array}{ccc}
1 & 1 & 4 \
1 & 0 & 1 \
0 & 1 & 3 end{array} ight)  o left( egin{array}{ccc}
1 & 0 & 1 \
0 & 1 & 3 \
0 & 0 & 0 end{array} ight)]

即得$x_0$=1,$x_1$=3
由题意 每种工具的加工时间为3到9天
故 $x_0$=8,$x_1$=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     else
11     {
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.
");
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("
");
148                 else
149                     printf(" ");
150             }
151             continue;
152         }
153         printf("Multiple solutions.
");
154     }
155     return 0;
156 }
POJ 2947
原文地址:https://www.cnblogs.com/Empress/p/4249444.html