蓝桥杯 ALGO-109 算法训练 貌似化学

算法训练 貌似化学

时间限制:1.0s 内存限制:512.0MB

 

问题描述
  现在有a,b,c三种原料,如果他们按x:y:z混合,就能产生一种神奇的物品d。
  当然不一定只产生一份d,但a,b,c的最简比一定是x:y:z
  现在给你3种可供选择的物品:
  每个物品都是由a,b,c以一定比例组合成的,求出最少的物品数,使得他们能凑出整数个d物品(这里的最少是指三者个数的总和最少)

 

输入格式
  第一行三个整数,表示d的配比(x,y,z)
  接下来三行,表示三种物品的配比,每行三个整数(<=10000)。

 

输出格式
  四个整数,分别表示在最少物品总数的前提下a,b,c,d的个数(d是由a,b,c配得的)
  目标答案<=10000
  如果不存在满足条件的方案,输出NONE

 

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

 

样例输出
8 1 5 7
 

分析:设a, b, c, d四种物品的个数分别为n_a, n_b, n_c, n_d,给定的三种物品的配比分别为

\begin{aligned} & o_{1x}, o_{1y}, o_{1z} \\ & o_{2x}, o_{2y}, o_{2z} \\ & o_{3x}, o_{3y}, o_{3z} \end{aligned} (即对应输入的第2~4行)

于是可以列出三元一次方程组

\begin{cases} o_{1x} n_a + o_{2x} n_b + o_{3x} n_c = n_d x \\ o_{1y} n_a + o_{2y} n_b + o_{3y} n_c = n_d y \\ o_{1z} n_a + o_{2z} n_b + o_{3z} n_c = n_d z \end{cases}

现要求出使得n_a, n_b, n_c均为正整数的最小的n_d

 

#include <stdio.h>

long long int det(long long int mat[3][3])
{
    return mat[0][0] * mat[1][1] * mat[2][2] +
            mat[1][0] * mat[2][1] * mat[0][2] +
            mat[2][0] * mat[0][1] * mat[1][2] -
            mat[2][0] * mat[1][1] * mat[0][2] -
            mat[1][0] * mat[0][1] * mat[2][2] -
            mat[0][0] * mat[2][1] * mat[1][2];
}

int solve(long long int A[3][3], long long int d[3], long long int *x, long long int *y, long long int *z)
{
    long long int delta = det(A);
    long long int delta_x, delta_y, delta_z;

    for (int k = 0; k < 3; ++k)
    {
        long long int A_rep[3][3] = { 0 };
        for (int j = 0; j < 3; ++j)
        {
            if (j == k)
            {
                for (int i = 0; i < 3; ++i)
                    A_rep[i][j] = d[i];
            }
            else
            {
                for (int i = 0; i < 3; ++i)
                    A_rep[i][j] = A[i][j];
            }
        }

        if (k == 0)
        {
            delta_x = det(A_rep);
            if (delta_x % delta != 0)
                return 0;
            *x = delta_x / delta;
            if (*x < 0)
                return 0;
        }
        else if (k == 1)
        {
            delta_y = det(A_rep);
            if (delta_y % delta != 0)
                return 0;
            *y = delta_y / delta;
            if (*y < 0)
                return 0;
        }
        else
        {
            delta_z = det(A_rep);
            if (delta_z % delta != 0)
                return 0;
            *z = delta_z / delta;
            if (*z < 0)
                return 0;
        }
    }
    return 1;
}

int main()
{
    long long A[3][3] = { 0 }, d[3] = { 0 };
    long long int x, y, z;
    long long int na, nb, nc, nd;

    scanf("%lld %lld %lld", &x, &y, &z);
    for (int j = 0; j < 3; ++j)
        for (int i = 0; i < 3; ++i)
            scanf("%lld", &A[i][j]);

    if (det(A) == 0)
    {
        printf("NONE");
        return 0;
    }

    for (nd = 1; nd <= 10000; ++nd)
    {
        d[0] = nd * x;
        d[1] = nd * y;
        d[2] = nd * z;

        if (solve(A, d, &na, &nb, &nc))
        {
            printf("%lld %lld %lld %lld", na, nb, nc, nd);
            return 0;
        }
    }
    printf("NONE");

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值