UVA 1397 - The Teacher's Side of Math(高斯消元)

UVA 1397 - The Teacher's Side of Math

题目链接

题意:给定一个x=a1/m+b1/n,求原方程组

思路:由于m*n最多20,所有最高项只有20,然后可以把每个此项拆分,之后得到n种不同无理数,每一项为0,就可以设系数为变元,构造方程进行高斯消元

一开始用longlong爆了,换成分数写法也爆了,又不想改高精度,最后是机智的用了double型过的,不过用double精度问题,所以高斯消元的姿势要正确,并且最后输出要注意-0的情况

代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

typedef long long ll;

const int N = 25;
const double eps = 1e-9;

ll a, m, b, n, C[N][N];
int hash[N][N], tot;

double A[N][N];

void build() {
    memset(A, 0, sizeof(A));
    A[0][0] = 1;
    for (int i = 1; i <= tot; i++) {
	for (int j = 0; j <= i; j++) {
	    int l = j, r = i - j;
	    double tmp = C[i][l] * pow(a * 1.0, l / m) * pow(b * 1.0, r / n);
	    l %= m; r %= n;
	    A[hash[l][r]][i] += tmp;
	}
    }
    A[tot][tot] = 1;
    A[tot][tot + 1] = 1;
    tot++;
}

void getC() {
    for (int i = 0; i <= 20; i++) {
	C[i][0] = C[i][i] = 1;
	for (int j = 1; j < i; j++)
	    C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
    }
}

void gethash() {
    tot = 0;
    for (int i = 0; i < m; i++) {
	for (int j = 0; j < n; j++) {
	    hash[i][j] = tot++;
	}
    }
}

void print(double x) {
    char s[100];
    sprintf(s, "%.0lf", x);
    if (strcmp(s, "-0") == 0) printf(" %s", s + 1);
    else printf(" %s", s);
}

void gauss() {
    for (int i = 0; i < tot; i++) {
	int r = i;
	for (int j = i + 1; j < tot; j++) {
	    if (fabs(A[j][i]) > fabs(A[r][i]))
		r = j;
	}
	if (fabs(A[r][i]) < eps) continue;
	for (int j = i; j <= tot; j++)
	    swap(A[r][j], A[i][j]);
	for (int j = 0; j < tot; j++) {
	    if (i == j) continue;
	    if (fabs(A[j][i]) >= eps) {
		double tmp = A[j][i] / A[i][i];
		for (int k = i; k <= tot; k++)
		    A[j][k] -= tmp * A[i][k];
	    }
	}
    }
    printf("1");
    for (int i = tot - 2; i >= 0; i--)
	print(A[i][tot] / A[i][i]);
    printf("\n");
}

int main() {
    getC();
    while (~scanf("%lld%lld%lld%lld", &a, &m, &b, &n)) {
	if (!a && !m && !b && !n) break;
	gethash();
	build();
	gauss();
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值