【例题】【高斯消元】USACO3.2.4 Feed Ratios

NKOJ1828 【USACO3.2.4】Feed Ratios饲料调配
时间限制 : 10000 MS 空间限制 : 65536 KB

问题描述
农夫约翰从来只用调配得最好的饲料来喂他的奶牛。饲料用三种原料调配成:大麦,燕麦和小麦。他知道自己的饲料精确的配比,在市场上是买不到这样的饲料的。他只好购买其他三种混合饲料(同样都由三种麦子组成),然后将它们混合,来调配他的完美饲料。
给出三组整数,表示 大麦:燕麦:小麦 的比例,找出用这三种饲料调配 x:y:z 的饲料的方法。
例如,给出目标饲料 3:4:5 和三种饲料的比例:
1:2:3
3:7:1
2:1:2
你必须编程找出使这三种饲料用量最少的方案,要是不能用这三种饲料调配目标饲料,输出“NONE”。“用量最少”意味着三种饲料的用量(整数)的和必须最小。

对于上面的例子,你可以用8份饲料1,1份饲料2,和5份饲料3,来得到7份目标饲料:
8*(1:2:3) + 1*(3:7:1) + 5*(2:1:2) = (21:28:35) = 7*(3:4:5)
表示饲料比例的整数以及目标饲料的都是小于100的非负整数。表示各种饲料的份数的整数,都小于100。一种混合物的比例不会由其他混合物的比例直接相加得到。

输入格式
Line 1: 三个用空格分开的整数,表示目标饲料
Line 2..4: 每行包括三个用空格分开的整数,表示农夫约翰买进的饲料的比例

输出格式
输出文件要包括一行,这一行要么有四个整数,要么是“NONE”。前三个整数表示三种饲料的份数,用这样的配比可以得到目标饲料。第四个整数表示混合三种饲料后得到的目标饲料的份数。

样例输入
3 4 5
1 2 3
3 7 1
2 1 2

样例输出
8 1 5 7

纯模板…

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int need=4;

#define abs(x) (x<0 ? -x : x)

int m[need][need+1],a[need][need+1];
int ans[need+1];
bool free_x[need];
int free_tot,free_id;

int LCM(int a,int b)
{
    int aa=a,bb=b;
    for(int t=a%b;t;a=b,b=t,t=a%b);
    return aa*bb/b;
}

int gauss(int xx,int yy)//x行 y列 
{
    int x=1,y=1,mx,lcm,aa,bb;
    for(int i,j;x<=xx&&y<yy;x++,y++)
    {
        mx=x;
        for(i=x+1;i<=xx;i++) if(abs(m[i][y])>abs(m[mx][y])) mx=i;
        if(x!=mx) 
         for(i=y;i<=yy;i++) swap(m[x][i],m[mx][i]); 
        if(m[x][y]==0) {x--;continue;}//m[x][y]为该列绝对值最大,若为0,后面都为0 
        for(i=x+1;i<=xx;i++)
         if(m[i][y])
         {
            lcm=LCM(m[i][y],m[x][y]);
            aa=lcm/m[x][y];
            bb=lcm/m[i][y];
            for(j=y;j<=yy;j++) m[i][j]=m[i][j]*bb-m[x][j]*aa;
         }
    }
    for(int i=x;i<=xx;i++) if(m[i][yy]!=0) return -1;//无解 
    if(x<xx) 
    {
        for(int i=1;i<=xx;i++) free_x[i]=true;
        for(int i=x-1,j,temp;i=1;i--)
        {
            free_tot=1;
            for(j=1;j<=yy;j++) 
             if(m[i][j]&&free_x[i])
             {
                free_tot++;
                free_id=i;
             }
            if(free_tot>1) continue;
            temp=m[i][yy];
            for(j=1;j<yy;j++)if(m[i][j]!=0&&free_id!=j) temp-=m[i][j]*ans[j];
            if(temp%m[i][i]!=0) return -2;
            ans[free_id]=temp/m[i][i];
            free_x[free_id]=false;
        }
        return (yy-1)-x;
    }
    int temp;
    for(int i=xx,j;i>=1;--i)
    {
        temp=m[i][y];
        for(j=i+1;j<yy;j++) temp-=m[i][j]*ans[j];
        if(temp%m[i][i]!=0) return -2;
        ans[i]=temp/m[i][i];
    }
    return 0;
}

#define END  {puts("NONE");return 0;}

int main()
{
    for(int i=1;i<=3;i++) cin>>a[i][4];
    for(int i=1;i<=3;i++)
     for(int j=1;j<=3;j++)
      cin>>a[j][i];
    int k=1;
    while(true)
    {
        for(int i=1;i<=3;i++) ans[i]=0,free_x[i]=true;
        memcpy(m,a,sizeof(a));
        for(int i=1;i<=3;i++) m[i][4]*=k;
        int t=gauss(3,4);
        if(t==-1) END
        if(t>=0) 
        {
            if(t==0) 
            {
                for(int i=1;i<=3;i++) if(ans[i]<0) END
                for(int i=1;i<=3;i++) cout<<ans[i]<<" "; 
            }
            else
            {
                for(int i=1;i<=3;i++) if(!free_x[i]&&ans[i]<0) END
                for(int i=1;i<=3;i++) cout<<(free_x[i] ? ans[i]: 0)<<" "; 
            }

            cout<<k;
            return 0;
        }
        if(t==-2) k++;
        if(k>300) END
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值