题解
本题比较麻烦的两个点
1.生成矩阵
2.将矩阵化成阶梯型
生成矩阵
思路是先确定这个矩阵有多少行多少列。再一个个填数字。可以观察到。1.矩阵的行
是原子的个数。2.矩阵的列数是化学式的个数。每次遇到原子放入set中,最后算下set的大小就能确定原子的个数. 化学式的个数是输入中已经给出的m.
之后开一个字典数组存下每个化学式中所包含的原子和个数.最后遍历矩阵填数字就完了.
详细见代码注释.
#include <iostream>
#include <map>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
const int N = 55;
const double eps = 1e-8;
double a[N][N]={0};
map<string, int> dict[N];
map<int,string> atom;
set<string> sset;
/*输入:4 al2s3o12 n1h5o1 al1o3h3 n2h8s1o4
atom[5]: { <0,al>, <1,s> <2,o> ,<3,n> ,<4,h>}
dict[4]:
{
{<al,2>, <s,3>, <o,1>} ,
{<n, 1>, <h,5>, <o,1>} ,
{<al,1>, <o,3>, <h,3>},
{<n,2>, <h,8>, <s,1>,<o,4>}
}
*/
bool isNumber(char c ){
if(c>='0'&&c<='9') return true;
return false;
}
int gauss(int n, int m){ //对矩阵化行阶梯型,用了y总高斯消元的模板
int r = 0 ,c = 0;
for(; c < m; c ++){
int t = r;
for(int i = r; i < n; i ++ )
if( fabs(a[i][c] ) > fabs( a[t][c] ) )
t=i;
if( fabs( a[t][c] ) < eps ) continue;
for(int j = c ; j < m; j ++)
swap(a[t][j],a[r][j]);
for(int j = m - 1; j >= c; j --)
a[r][j]/=a[r][c];
for(int i = r + 1 ; i < n ; i ++ ){
if(fabs(a[i][c]) < eps ) continue;
double k = a[i][c];
for(int j = c; j < m ; j ++)
a[i][j]-=a[r][j] * k;
}
r++;
}
if( r < m ){ //r代表矩阵的秩,矩阵的秩小于未知量的个数就有解.
return 1;
}
return 0;
}
void init(){
atom.clear();
sset.clear();
for(int i=0;i<N;i++)
dict[i].clear();
for(int i=0;i<N;i++)
for(int j=0; j<N; j++)
a[i][j]=0;
}
int main(){
int T;
cin>>T;
while(T--){
init();
int n=0,m;
cin>>m;
// n是行数 , m是列数
for(int i = 0; i < m; i ++){
string s;
cin>>s;
int index=0;
for(int c=0;c<s.length();c++){
if(!isNumber(s[c])) continue;
int x=0;
string t; //存放原子字符串
while( isNumber(s[c]) ){
if(x==0) t=s.substr(index, c-index);
x=x*10+s[c]-'0';
c++;
}
index=c;
if(sset.find(t)==sset.end()){
atom[n++]=t;
}
sset.insert(t);
dict[i][t] =x;
}
}
for(int i=0;i<n; i++){
for(int j=0;j<m;j++){
if(dict[j].find(atom[i])!=dict[j].end()){
a[i][j]=dict[j][atom[i]];
}
}
}
int ans = gauss(n,m);
if(ans) cout<<"Y\n";
else cout << "N\n";
}
return 0;
}