AOJ 1328 Find the Outlier

問題

xのd次式f(x)がある。
f(x)に、x = 0, 1, 2, ..., d + 2を代入した結果v[0], v[1], ..., v[d + 2]が与えられる。

このうち、どれか1つは間違った数字になっている。
このとき、その数字を見つけよ。

制約条件

d≦5

v[i] ≦100

方針

2つを取り除いて連立式を作り、f(x)の形を具体的に求める。
このf(x)を使って逆にv[0], ..., v[d + 2]を計算し、外れている値がちょうど1つであるかどうかを見る。


EPSを適当にすると通らないので、10^-9から、答えがユニークになるまで
EPSを10倍しながら同じ解法を繰り返したら通った。

ソースコード

連立方程式の解はspaghetti sourceより。

int n;
double v[10];

vector<double> solve2(int i1, int i2){
	matrix M(n + 1, array(n + 1));
	array b(n + 1);
	int r = 0;
	rep(i, n + 3) if(i != i1 && i != i2){
		rep(j, n + 1) M[r][j] = j ? pow(i * 1.0, j) : 1.0;
		b[r++] = v[i];
	}
	LUinfo data = LU_decomposition(M);
	b = LU_backsubstitution(data, b);
	
	vector<double> res;
	rep(i, n + 3){
		double tmp = 0;
		rep(j, n + 1) tmp += (j ? pow(i * 1.0, j) : 1.0) * b[j];
		res.pb(tmp);
	}
	return res;
}
double EPS;
double solve(int idx){
	double err;
	rep(it, n + 3) if(it != idx){
		vector<double> res = solve2(idx, it);
		if(abs(res[it] - v[it]) > EPS) return 1e12;
		err = abs(res[it] - v[idx]);
	}
	return err;
}
int main(){
	while(cin >> n, n){
		rep(i, n + 3) cin >> v[i];
		for(EPS = 1e-9; ; EPS *= 10){
			double mnerr = 1e12; int mni = -1;
			rep(i, n + 3){
				double err = solve(i);
				if(err < mnerr) mnerr = err, mni = i;
			}
			if(mni >= 0){
				cout << mni << endl;
				break;
			}
		}
	}
	return 0;
}