P5027 【Barracuda】

适合初学高斯消元

题目还是很好理解的,每次给定几个三角形和重量,就可以建立\(n+1\)个方程,转化为高斯消元模板

想一想高斯消元的模板长什么样子,一个\(n*(n+1)\)的矩阵,但是按照上面的思路来建立的话,会搞出来一个\((n+1)*(n+1)\)的矩阵,那么就会遇到一些坑

思路就是假设每一行都是错误的情况

  1. 并不是每一个编号的系数为\(1\),最开始我这里想了很久,可以抓多次同个三角形

  2. 如何假设是\(x\)行出错,对于高斯消元时的处理,并不能直接\(continue\)当前行,还是应该存储一个模板矩阵

然后就继续说如何判断题目中的条件

  1. 最重的三角形只有一个,我们只需要在回代过后,对\(maxx\)的个数记录一下即可

  2. 不存在重量不确定的三角形,说明该方程在转化为“上三角形”之后,出现了\(0=0\)这类恒等式,表示无数组解,当然无解也是这样

  3. 三角形重量是正整数,我们用\(duoble\)来存储答案,如果\(int\)强制转换后的值比\(duoble\)类型小,说明不是正整数

  4. 对于不是合法方案,其实就是相当于当\(i\)错误时,我们能求出来一组解,当\(j\)错误时,我们也能求出来一组解,说明\(illegal\)

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-6;
double a[150][150];
double b[150][150];
int n,m,x;
int maxx,pre;
int gauss() {
	int c,r;
	for(c=1,r=1; c<=n; c++) {
		int t=r;
		for(int i=r; i<=n; i++) {
			if(fabs(a[t][c])<fabs(a[i][c])) t=i;
		}
		if(fabs(a[t][c])<eps) return 0;
		for(int i=c; i<=n+1; i++) swap(a[r][i],a[t][i]);
		for(int i=n+1; i>=c; i--) a[r][i]/=a[r][c];
		for(int i=r+1; i<=n; i++) {
			if(fabs(a[i][c])>eps) {
				for(int j=n+1; j>=c; j--) a[i][j]-=a[r][j]*a[i][c];
			}
		}
		r++;
	} //高斯消元模板 
	for(int i=n; i>=1; i--) {
		for(int j=i+1; j<=n; j++) {
			a[i][n+1]-=a[j][n+1]*a[i][j];
		}
		if(a[i][n+1]<eps||((int)a[i][n+1])<a[i][n+1]) return 0; //无解或是重量为小数的情况 
	} //回代 
	int sum;
	maxx=-1;
	for(int i=1; i<=n; i++) {
		if((int)a[i][n+1]>maxx) maxx=a[i][n+1],sum=i;
	} //记录最值 
	int num=0;
	for(int i=1; i<=n; i++) {
		if((int)a[i][n+1]==maxx) num++; //最值数量 
	}
	if(num>1) return 0;
	return sum;
}
int tot;
int main() {
	scanf("%d",&n);
	for(int i=1; i<=n+1; i++) {
		scanf("%d",&m);
		for(int j=1; j<=m; j++) {
			scanf("%d",&x);
			b[i][x]++;
		}
		scanf("%d",&x);
		b[i][n+1]=x*1.0;
	} //存储初始的(n+1)*(n+1)的矩阵 
	for(int i=1; i<=n+1; i++) {
		int cnt=0;
		for(int h=1; h<=n+1; h++) {
			if(h==i) continue;
			cnt++;
			for(int k=1; k<=n+1; k++) {
				a[cnt][k]=b[h][k];
			}
		} //存储一个n*(n+1)的矩阵 
		int p=gauss();
		if(p==0) continue; //无解或者无数组解 
		else tot++,pre=p; //tot表示有几组解,pre是答案 
	}
	if(tot>1||tot==0) puts("illegal"); //全部无解或者出现多组解 
	else cout<<pre;  
	return 0;
}
posted @ 2020-09-15 13:26  Poetic_Rain  阅读(20)  评论(0编辑  收藏