题解 炼金术士的疑惑

传送门

考场上把这题恶心的读入写完,把高斯消元的板子打完,觉得未知数大于方程个数没法解就没交……
事实上直接交上去有75pts,血亏

  • 其实高斯消元有个性质:即使出现不合法情况,其解出的结果也一定是一组合法解。这个性质用在类似这题可以骗到不少分,
    因为这题数据保证有解,所以解出来每种元素的焓可能是错的,但对它们按系数比求和一般是对的
    其实这题是高斯消元的另一种神奇用法,把要求解的方程一起带进去加减消元即可
  • 开题分四步:算空间,看输入格式/范围,查精度,手模一组样例验证题意
  • 剩的时间不多了一定要静态查错,尤其是状态不太好的时候,容易打错各种细节

这题其实是高斯消元一个神奇的情况:我们求不出每个未知数具体的值,但我们能用它表示出答案
WG4kg1.png
记个性质吧……考场上还真想不到能这么搞

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 230
#define ll long long 
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long 

inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, tot;
map<string, int> mp;
string s, t;
double ans[N];
const double eps=1e-10;

struct matrix{
	int n, m;
	double a[N][N];
	void resize(int i, int j) {n=i; m=j;}
	inline double* operator [] (int i) {return a[i];}
	void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<a[i][j]<<' '; cout<<endl;}}
	void gauss() {
		for (int i=1; i<=n; ++i) {
			int r=i;
			for (int j=i+1; j<=n; ++j) if (fabs(a[j][i])>fabs(a[r][i])) r=j;
			if (i!=r) swap(a[i], a[r]);
			for (int j=1; j<=n; ++j) {
				if (i==j) continue;
				if (fabs(a[i][i])<eps) continue;
				double d=a[j][i]/a[i][i];
				for (int k=1; k<=m; ++k) a[j][k] -= a[i][k]*d;
			}
			if (fabs(a[n+1][i])>eps) {
				double d=a[n+1][i]/a[i][i];
				for (int k=1; k<=m; ++k) a[n+1][k] -= a[i][k]*d;
			}
		}
		for (int i=1; i<=n; ++i) ans[i]=a[i][m]/a[i][i];
		//for (int i=1; i<=n; ++i) cout<<ans[i]<<' '; cout<<endl;
	}
}mat;

inline double tran() {
	//cout<<"tran "<<s<<endl;
	double ans=0, f=1, e=0.1, len=s.length(), pos=0;
	char c=s[pos++];
	while (!isdigit(c)) {if (c=='-') f=-f; c=s[pos++];}
	while (pos<=len) {if (c=='.') break; ans=ans*10+(c^48); c=s[pos++];}
	//cout<<"ans: "<<ans<<endl;
	if (c=='.') {
		c=s[pos++];
		//cout<<"c: "<<c<<endl;
		while (pos<=len) {ans+=e*(c^48); e/=10; c=s[pos++];}
	}
	//cout<<"return "<<ans*f<<endl;
	return ans*f;
}

signed main()
{
	#ifdef DEBUG
	freopen("1.in", "r", stdin);
	#endif
	double h, ans2=0;
	
	n=read();
	mat.resize(n, 205);
	for (int i=1; i<=n; ++i) {
		while (1) {
			cin>>s;
			if (isdigit(s[0])) {
				h=tran();
				cin>>s;
				if (!mp[s]) mp[s]=++tot;
				//cout<<mp[s]<<endl;
				mat[i][mp[s]]=h;
				//cout<<t2<<endl;
			}
			else if (s[0]=='=') break;
		}
		while (1) {
			cin>>s;
			if (isdigit(s[0])) {
				h=tran();
				cin>>s;
				if (!mp[s]) mp[s]=++tot;
				mat[i][mp[s]]=-h;
				//cout<<-t2<<endl;
			}
			else if (s[0]=='H') break;
		}
		cin>>h;
		mat[i][205]=h;
		//cout<<h<<endl;
	}
	while (1) {
		cin>>s;
		if (isdigit(s[0])) {
			h=tran();
			cin>>s;
			mat[n+1][mp[s]]=h;
		}
		else if (s[0]=='=') break;
	}
	while (1) {
		cin>>s;
		if (isdigit(s[0])) {
			h=tran();
			cin>>s;
			mat[n+1][mp[s]]=-h;
		}
		else if (s[0]=='H') break;
	}
	//mat.put(); cout<<endl;
	mat.gauss();
	//mat.put(); cout<<endl;
	printf("%.1lf\n", -mat[n+1][205]+eps);

	return 0;
}
posted @ 2021-07-19 14:28  Administrator-09  阅读(28)  评论(1编辑  收藏  举报