POJ2947 Widget Factory 高斯消元+扩展GCD解同余方程组

题目链接:http://poj.org/problem?id=2947


题目大意:有n 种装饰物,m 个已知条件,每个已知条件的描述如下:
p start end
a1,a2......ap (1<=ai<=n)
第一行表示从星期start 到星期end 一共生产了p 件装饰物(工作的天数为end-start+1+7*x,加7*x 是因为它可能生产很多周),第二行表示这p 件装饰物的种类(可能出现相同的种类,即ai=aj)。规定每件装饰物至少生产3 天,最多生产9 天。问每种装饰物需要生产的天数。如果没有解,则输出“Inconsistent data.”,如果有多解,则输出“Multiple solutions.”,如果只有唯一解则输出每种装饰物需要生产的天数。


分析:高斯消元。设每种装饰物需要生产的天数为xi(1<=i<=n)。每一个条件就相当于给定了一个方程式,假设生产1 类装饰物a1 件、2 类装饰物a2 件、i 类装饰物ai 件所花费的天数为b,则可以列出下列方程:

a1*x1+a2*x2+...an*xn = b (mod 7);

这样一共可以列出m 个方程式,然后使用高斯消元来解此方程组即可。


实现代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int inf=0x3fffffff;
const int maxn=300;
int a[maxn][maxn+1],x[maxn];//a是系数矩阵和增广矩阵,x存放最后的解
int equ,var,free_n;//equ是系数矩阵的行数,var个变元(即系数矩阵的列数)
void Debug()
{
   for(int i=0;i<equ;i++)
   {
      for(int j=0;j<var+1;j++)
        cout<<a[i][j]<<" ";
      cout<<endl;
   }
}
int exc(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;
}
void Init()
{
    int p,d;
    char s1[5],s2[5];
    memset(a,0,sizeof(a));
    memset(x,0,sizeof(x));
    for(int i=0;i<equ;i++)
    {
        scanf("%d%s%s",&p,s1,s2);
        a[i][var]=( ( exc(s2)-exc(s1) )%7+8 )%7;
        for(int j=0;j<p;j++)
        {
            scanf("%d",&d);
            a[i][d-1]++; //题中类别由1到n,故需要减1
            a[i][d-1]%=7;
        }
    }
}
int min(int a,int b)
{
    return a<b?a:b;
}
int gcd(int a,int b)
{
    if(a<0) return gcd(-a,b);
    if(b<0) return gcd(a,-b);
    return b==0?a:gcd(b,a%b);
}
int ex_gcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
         x=1,y=0;
         return a;
    }
    int ret=ex_gcd(b,a%b,x,y);
    int tmp=x;
    x=y;
    y=tmp-a/b*y;
    return ret;
}
void Gauss()
{
    int k,col=0; //当前处理的列
    for(k=0;k<equ&&col<var;k++,col++)
    {
        int mx=k;
        for(int i=k+1;i<equ;i++)
          if(a[i][col]>a[mx][col]) mx=i;
        if(mx!=k)
          for(int i=k;i<var+1;i++) swap(a[k][i],a[mx][i]);
        if(!a[k][col]) { k--; continue; }
        for(int i=k+1;i<equ;i++)
          if(a[i][col]!=0)
          {
              int lcm=a[k][col] / gcd(a[k][col],a[i][col]) * a[i][col];
              int ta=lcm/a[i][col], tb=lcm/a[k][col];
              if(a[i][col]*a[k][col]<0) tb=-tb;
              for(int j=col;j<var+1;j++)
                a[i][j]=( (a[i][j]*ta)%7 - (a[k][j]*tb)%7 +7 )%7;
          }
    }
    //Debug();
    for(int i=k;i<equ;i++)
      if(a[i][col]!=0)
      {
          puts("Inconsistent data.");
          return ;
      }
    if(k<var)
    {
        puts("Multiple solutions.");
        return ;
    }
    for(int i=0,j;i<equ;i++) //每一行主元素化为非零
      if(!a[i][i])
      {
          for(j=i+1;j<var;j++)
            if(a[i][j]) break;
          if(var<=j) break;
          for(int r=0;r<equ;r++) swap(a[r][i],a[r][j]);
      }
    for(int i=k-1;i>=0;i--)
    {
        int tmp=a[i][var]%7,x1,y;
        for(int j=i+1;j<var;j++)
           if(a[i][j]) tmp=((tmp-x[j]*a[i][j])%7+7)%7;
        int gcd=ex_gcd(a[i][i],7,x1,y);
        x[i]=(x1*tmp/gcd%7+7)%7;
    }
    for(int i=0;i<var;i++)
       if(x[i]<3) x[i]+=7;
    printf("%d",x[0]);
    for(int i=1;i<var;i++)
      printf(" %d",x[i]);
    puts("");
}
int main()
{
    while(scanf("%d%d",&var,&equ))
    {
        if(var==0&&equ==0) break;
        Init();
        Gauss();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值