1. 程式人生 > 實用技巧 >ALGO-109 貌似化學 逆矩陣

ALGO-109 貌似化學 逆矩陣

/*
演算法訓練 貌似化學 

資源限制
時間限制:1.0s   記憶體限制:256.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
*/

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

typedef long long ll;

ll ans[4];
ll b[4];
ll c[4][4];
ll A[4][4]; //伴隨矩陣

ll gcd(ll a, ll b)
{
    if(!b) return a;
    return gcd(b, a%b);
}

void fun()
{
    //求伴隨矩陣(不求逆矩陣,因為可能出現分式,在計算的結果最後取最大公約數)
    for (int i = 0; i < 3; i++)
		for (int j = 0; j < 3; j++) 
        {
            //計算餘子式
			int minr, maxr, minc, maxc; //row carry
			minc = min((i + 1) % 3, (i + 2) % 3), maxc = max((i + 1) % 3, (i + 2) % 3);
			minr = min((j + 1) % 3, (j + 2) % 3), maxr = max((j + 1) % 3, (j + 2) % 3);
			A[i][j] = pow (-1, i + j) * (c[minr][minc] * c[maxr][maxc] - c[maxr][minc] * c[minr][maxc]);
		}
    
    //矩陣乘法
    for(int i = 0; i < 3; i++) ans[i] = b[0]*A[0][i]+b[1]*A[1][i]+b[2]*A[2][i];

    if(ans[1] < 0 || ans[2] < 0 || ans[0] < 0) ans[0] = -ans[0], ans[1] = -ans[1], ans[2] = -ans[2];
    if(ans[1] < 0 || ans[2] < 0 || ans[0] < 0) cout << "NONE";  //不是都為負數,則不存在結果
    else
    {
        ll tmp = gcd(ans[1], ans[2]);
        tmp = gcd(tmp, ans[0]);
        ans[1] /= tmp;
        ans[2] /= tmp;
        ans[0] /= tmp;
        cout << ans[0] << ' ' << ans[1] << ' ' << ans[2] << ' ' << (ans[0]*c[0][0]+ans[1]*c[1][0]+ans[2]*c[2][0])/b[0];
    }
}

int main()
{
    cin >> b[0] >> b[1] >> b[2];
    for(int i = 0; i < 3; i++)
        for(int j = 0; j < 3; j++)
            cin >> c[i][j];
    
    fun();
    system("pause");
    return 0;
}