[Gauss]POJ2947 Widget Factory

时间:2024-09-28 22:33:38

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

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

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

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

可以列出同余方程组:$\sum\limits_{i=0}^{n-1} a_i×x_i\equiv 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( \begin{array}{ccc}
1 & 1 & 4 \\
2 & 1 & 5 \\
1 & 2 & 7 \end{array} \right) \to \left( \begin{array}{ccc}
1 & 1 & 4 \\
1 & 0 & 1 \\
0 & 1 & 3 \end{array} \right) \to \left( \begin{array}{ccc}
1 & 0 & 1 \\
0 & 1 & 3 \\
0 & 0 & 0 \end{array} \right)\]

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

下面是代码:

有mod就会有要求逆元
两种求逆元的方法 1. extend gcd
注意得到的x可能为负 要x=(x%mod+mod)%mod;
 void ex_gcd(int a, int b, int &x, int &y)
{
if(b)
{
ex_gcd(b, a%b, x, y);
int tmp=x;
x=y;
y=tmp-(a/b)*y;
}
else
{
x=, y=;
return ;
}
}

2.inverse element

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

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

此题还有一法不求逆元:(利用欧拉函数)

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

 while(tmp%a[i][i])
tmp+=mod;
x[i]=(tmp/a[i][i])%mod; 与以下等价 int xx, yy;
ex_gcd(a[i][i], mod, xx, yy);
xx=(xx%mod+mod)%mod;
x[i]=(tmp*xx)%mod; 与以下等价 x[i]=(tmp*inv(a[i][i], mod))%mod;

完整代码:

 const int mod=;
int gcd(int a, int b)
{
return b==? a:gcd(b, a%b);
}
int lcm(int a, int b)
{
return a/gcd(a, b)*b;
}
void ex_gcd(int a, int b, int &x, int &y)
{
if(b)
{
ex_gcd(b, a%b, x, y);
int tmp=x;
x=y;
y=tmp-(a/b)*y;
}
else
{
x=, y=;
return ;
}
} int a[][]; // 增广矩阵
int x[]; // 解
int free_x[]; // 标记是否为*未知量 int Gauss(int n, int m) // n个方程 m个未知数 即 n行m+1列
{
//转换为阶梯形式
int col=, k, num=;
for(k=;k<n && col<m;k++, col++)
{//枚举行
int max_r=k;
for(int i=k+;i<n;i++)//找到第col列元素绝对值最大的那行与第k行交换
if(abs(a[i][col])>abs(a[max_r][col]))
max_r=i;
if(max_r!=k)// 与第k行交换
for(int j=col;j<m+;j++)
swap(a[k][j], a[max_r][j]);
if(!a[k][col])// 说明该col列第k行以下全是0了
{
k--;
free_x[num++]=col;
continue;
}
for(int i=k+;i<n;i++)// 枚举要删除的行
if(a[i][col])
{
int LCM=lcm(abs(a[i][col]), abs(a[k][col]));
int ta=LCM/abs(a[i][col]);
int tb=LCM/abs(a[k][col]);
if(a[i][col]*a[k][col]<)
tb=-tb;
for(int j=col;j<m+;j++)
a[i][j]=((a[i][j]*ta-a[k][j]*tb)%mod+mod)%mod;
}
} for(int i=k;i<n;i++)
if(a[i][col])
return -; // 无解 if(k<m) //m-k为*未知量个数
return m-k; // 唯一解 回代
for(int i=m-;i>=;i--)
{
int tmp=a[i][m];
for(int j=i+;j<m;j++)
{
if(a[i][j])
tmp-=a[i][j]*x[j];
tmp=(tmp%+)%;
}
int xx, yy;
ex_gcd(a[i][i], mod, xx, yy);
xx=(xx%mod+mod)%mod;
x[i]=(tmp*xx)%mod;
}
return ;
} void init()
{
memset(a, , sizeof(a));
memset(x, , sizeof(x));
} int change(char c1, char c2)
{
if(c1=='M')
return ;
if(c1=='T' && c2=='U')
return ;
if(c1=='W')
return ;
if(c1=='T')
return ;
if(c1=='F')
return ;
if(c1=='S' && c2=='A')
return ;
return ;
} char s1[], s2[];
int main()
{
int n, m;
while(~scanf("%d%d", &n, &m))
{
if(!n && !m)
break;
init();
for(int i=;i<m;i++)
{
int X;
scanf("%d%s%s", &X, s1, s2);
a[i][n]=((change(s2[], s2[])-change(s1[], s1[])+)%mod+mod)%mod;
while(X--)
{
int t;
scanf("%d", &t);
a[i][t-]=(a[i][t-]+)%mod;
}
}
int t=Gauss(m, n);
if(t==-)
{
printf("Inconsistent data.\n");
continue;
}
if(t==)
{
for(int i=;i<n;i++)
if(x[i]<=)
x[i]+=;
for(int i=;i<n;i++)
{
printf("%d", x[i]);
if(i==n-)
printf("\n");
else
printf(" ");
}
continue;
}
printf("Multiple solutions.\n");
}
return ;
}

POJ 2947