总览:
两种方法:回代和约旦。(约旦不知道比回代高到哪里去了)
思路都是加减消元。
注意无解和无穷解。
只要列出方程就是模板…(可是方程列不出) (:逃
神仙博客:传送门
T1 P3389 【模板】高斯消元法
(洛谷P3389)
题目背景
Gauss消元
题目描述
给定一个线性方程组,对其求解
输入格式
第一行,一个正整数
n
n
n
第二至 n + 1 n+1 n+1行,每行 n + 1 n+1 n+1个整数,为 a 1 , a 2 . . . a n a_1, a_2 ...a_n a1,a2...an和 b b b,代表一组方程。
输出格式
共
n
n
n行,每行一个数,第
i
i
i行为
x
i
x_i
xi(保留2位小数)
如果不存在唯一解,在第一行输出"No Solution".
输入输出样例
输入
3
1 3 4 5
1 4 7 3
9 3 2 2
输出
-0.97
5.18
-2.39
说明/提示
1
≤
n
≤
100
,
∣
a
i
∣
≤
1
0
4
,
∣
b
∣
≤
1
0
4
1\le n\le 100,|a_i|\le 10^4,|b|\le 10^4
1≤n≤100,∣ai∣≤104,∣b∣≤104
注意:
1.
d
o
u
b
l
e
double
double的地方不能用
i
n
t
int
int;
2.实数比较需做差。
代码:
#include<bits/stdc++.h>
using namespace std;
const double EPS=1e-7;
int n;
double mapp[105][105];
bool compare(double x,double y){
if(fabs(x)-fabs(y)>EPS) return 1;
return 0;
}
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n+1;j++)
scanf("%lf",&mapp[i][j]);
for(int i=1;i<=n;i++){
int u=i;
for(int j=i+1;j<=n;j++)
if(!compare(mapp[u][i],mapp[j][i]))
u=j;
if(u!=i) swap(mapp[u],mapp[i]);
if(!compare(mapp[i][i],0)){
printf("No Solution");
return 0;
}
for(int j=1;j<=n;j++){
if(i==j) continue;
double div=mapp[j][i]/mapp[i][i];
for(int k=i+1;k<=n+1;k++)
mapp[j][k]-=mapp[i][k]*div;
}
}
for(int i=1;i<=n;i++)
printf("%0.2lf\n",mapp[i][n+1]/mapp[i][i]);
return 0;
}
T2 P2455 [SDOI2006]线性方程组
(洛谷P2455)
题目描述
已知
n
n
n元线性一次方程组。
其中:
n
<
=
50
n<=50
n<=50, 系数是整数
<
=
100
<=100
<=100(有负数),bi的值都是整数且
<
300
<300
<300(有负数)
编程任务:
根据输入的数据,编程输出方程组的解的情况。
输入格式
第一行:未知数的个数。以下
n
n
n行
n
+
1
n+1
n+1列:分别表示每一格方程的系数及方程右边的值。
输出格式
如果方程组无实数解输出
−
1
-1
−1;
如果有无穷多实数解,输出
0
0
0;
如果有唯一解,则输出解(小数点后保留两位小数)。
输入输出样例
输入
3
2 -1 1 1
4 1 -1 5
1 1 1 0
输出
x1=1.00
x2=0
x3=-1.00
一道高斯消元的题卡高斯消元…
和模板一样,但需注意判无解和无穷解。
当
m
a
p
p
[
i
]
[
i
]
=
0
并
且
m
a
p
p
[
i
]
[
n
+
1
]
≠
0
mapp[i][i]=0并且mapp[i][n+1]\neq 0
mapp[i][i]=0并且mapp[i][n+1]=0时,方程无解(
即
为
0
×
a
=
b
(
b
≠
0
)
即为0\times a=b(b\neq 0)
即为0×a=b(b=0))
当
m
a
p
p
[
i
]
[
i
]
=
0
并
且
m
a
p
p
[
i
]
[
n
+
1
]
=
0
mapp[i][i]=0并且mapp[i][n+1]=0
mapp[i][i]=0并且mapp[i][n+1]=0时,方程有无穷解(
即
为
0
×
a
=
0
即为0\times a=0
即为0×a=0)
最后注意解出
x
=
0
x=0
x=0时,输出
x
i
=
0
x_i=0
xi=0,而不是
x
i
=
0.00
x_i=0.00
xi=0.00。
代码:
#include<bits/stdc++.h>
using namespace std;
const double EPS=1e-7;
int n;
double mapp[55][55];
bool compare(double x,double y){
if(fabs(x)-fabs(y)>EPS) return 1;
return 0;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n+1;j++)
scanf("%lf",&mapp[i][j]);
for(int i=1;i<=n;i++){
int u=i;
for(int j=i+1;j<=n;j++)
if(!compare(mapp[u][i],mapp[j][i]))
u=j;
if(u!=i) swap(mapp[u],mapp[i]);
if(!compare(mapp[i][i],0)) continue;
for(int j=1;j<=n;j++){
if(i==j) continue;
double div=mapp[j][i]/mapp[i][i];
for(int k=i+1;k<=n+1;k++)
mapp[j][k]-=mapp[i][k]*div;
}
}
for(int i=1;i<=n;i++)
if(!compare(mapp[i][i],0)&&compare(mapp[i][n+1],0)){
printf("-1\n");
return 0;
}
for(int i=1;i<=n;i++)
if(!compare(mapp[i][i],0)&&!compare(mapp[i][n+1],0)){
printf("0\n");
return 0;
}
for(int i=1;i<=n;i++){
if(compare(mapp[i][n+1]/mapp[i][i],0)) printf("x%d=%0.2lf\n",i,mapp[i][n+1]/mapp[i][i]);
else printf("x%d=0\n",i);
}
return 0;
}
T3 P4035 [JSOI2008]球形空间产生器
(洛谷P4035)
题目描述
有一个球形空间产生器能够在
n
n
n 维空间中产生一个坚硬的球体。现在,你被困在了这个
n
n
n 维球体中,你只知道球面上
n
+
1
n+1
n+1 个点的坐标,你需要以最快的速度确定这个
n
n
n 维球体的球心坐标,以便于摧毁这个球形空间产生器。
输入格式
第一行是一个整数
n
n
n
(
1
<
=
N
=
10
)
(1<=N=10)
(1<=N=10)。接下来的
n
+
1
n+1
n+1 行,每行有
n
n
n 个实数,表示球面上一点的
n
n
n 维坐标。每一个实数精确到小数点后
6
6
6 位,且其绝对值都不超过
20000
20000
20000。
输出格式
有且只有一行,依次给出球心的
n
n
n 维坐标(
n
n
n 个实数),两个实数之间用一个空格隔开。每个实数精确到小数点后
3
3
3 位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。
输入输出样例
输入
2
0.0 0.0
-1.0 1.0
1.0 0.0
输出
0.500 1.500
说明/提示
提示:
给出两个定义:
球心:到球面上任意一点距离都相等的点。
距离:设两个n为空间上的点A, B的坐标为
(
a
1
,
a
2
.
.
.
a
n
)
,
(
b
1
,
b
2
.
.
.
b
n
)
(a_1,a_2...a_n),(b_1,b_2...b_n)
(a1,a2...an),(b1,b2...bn),则AB的距离定义为:
d
i
s
t
=
(
a
1
−
b
1
)
2
+
(
a
2
−
b
2
)
2
+
.
.
.
+
(
a
n
−
b
n
)
2
dist=\sqrt{(a_1-b_1)^2+(a_2-b_2)^2+...+(a_n-b_n)^2}
dist=(a1−b1)2+(a2−b2)2+...+(an−bn)2
思路:
导出方程后套模板…
导出方程:
设中心坐标
r
1
,
r
2
.
.
.
r
n
r_1,r_2...r_n
r1,r2...rn。
球的半径为
s
s
s。
首先列出方程:
(
a
1
−
r
1
)
2
+
(
a
2
−
r
2
)
2
+
.
.
.
+
(
a
n
−
r
n
)
2
=
s
\sqrt{(a_1-r_1)^2+(a_2-r_2)^2+...+(a_n-r_n)^2}=s
(a1−r1)2+(a2−r2)2+...+(an−rn)2=s
(
b
1
−
r
1
)
2
+
(
b
2
−
r
2
)
2
+
.
.
.
+
(
b
n
−
r
n
)
2
=
s
\sqrt{(b_1-r_1)^2+(b_2-r_2)^2+...+(b_n-r_n)^2}=s
(b1−r1)2+(b2−r2)2+...+(bn−rn)2=s
.
.
.
(
k
1
−
r
1
)
2
+
(
k
2
−
r
2
)
2
+
.
.
.
+
(
k
n
−
r
n
)
2
=
s
\sqrt{(k_1-r_1)^2+(k_2-r_2)^2+...+(k_n-r_n)^2}=s
(k1−r1)2+(k2−r2)2+...+(kn−rn)2=s
去根号:
(
a
1
−
r
1
)
2
+
(
a
2
−
r
2
)
2
+
.
.
.
+
(
a
n
−
r
n
)
2
=
s
2
(a_1-r_1)^2+(a_2-r_2)^2+...+(a_n-r_n)^2=s^2
(a1−r1)2+(a2−r2)2+...+(an−rn)2=s2
(
b
1
−
r
1
)
2
+
(
b
2
−
r
2
)
2
+
.
.
.
+
(
b
n
−
r
n
)
2
=
s
2
(b_1-r_1)^2+(b_2-r_2)^2+...+(b_n-r_n)^2=s^2
(b1−r1)2+(b2−r2)2+...+(bn−rn)2=s2
.
.
.
(
k
1
−
r
1
)
2
+
(
k
2
−
r
2
)
2
+
.
.
.
+
(
k
n
−
r
n
)
2
=
s
2
(k_1-r_1)^2+(k_2-r_2)^2+...+(k_n-r_n)^2=s^2
(k1−r1)2+(k2−r2)2+...+(kn−rn)2=s2
开括号:
(
a
1
2
+
a
2
2
+
.
.
.
+
a
n
2
)
+
(
r
1
2
+
r
2
2
.
.
.
+
r
n
2
)
−
2
×
(
a
1
×
r
1
+
a
2
×
r
2
.
.
.
a
n
×
r
+
n
)
(a_1^2+a_2^2+...+a_n^2)+(r_1^2+r_2^2...+r_n^2)-2\times (a_1\times r_1+a_2\times r_2...a_n\times r+n)
(a12+a22+...+an2)+(r12+r22...+rn2)−2×(a1×r1+a2×r2...an×r+n)
(
b
1
2
+
b
2
2
+
.
.
.
+
b
n
2
)
+
(
r
1
2
+
r
2
2
.
.
.
+
r
n
2
)
−
2
×
(
b
1
×
r
1
+
b
2
×
r
2
.
.
.
b
n
×
r
+
n
)
(b_1^2+b_2^2+...+b_n^2)+(r_1^2+r_2^2...+r_n^2)-2\times (b_1\times r_1+b_2\times r_2...b_n\times r+n)
(b12+b22+...+bn2)+(r12+r22...+rn2)−2×(b1×r1+b2×r2...bn×r+n)
.
.
.
(
k
1
2
+
k
2
2
+
.
.
.
+
k
n
2
)
+
(
r
1
2
+
r
2
2
.
.
.
+
r
n
2
)
−
2
×
(
k
1
×
r
1
+
k
2
×
r
2
.
.
.
k
n
×
r
+
n
)
(k_1^2+k_2^2+...+k_n^2)+(r_1^2+r_2^2...+r_n^2)-2\times (k_1\times r_1+k_2\times r_2...k_n\times r+n)
(k12+k22+...+kn2)+(r12+r22...+rn2)−2×(k1×r1+k2×r2...kn×r+n)
相邻上下两式相减,消去
r
2
r^2
r2和
s
s
s:
(
b
1
−
a
1
)
×
r
1
+
(
b
2
−
a
2
)
×
r
2
+
.
.
.
+
(
b
n
−
a
n
)
×
r
n
=
(
b
1
2
−
a
1
2
+
b
2
2
−
a
2
2
+
.
.
.
+
b
n
2
−
a
n
2
)
/
2
(b_1-a_1)\times r_1+(b_2-a_2)\times r_2+...+(b_n-a_n)\times r_n=(b_1^2-a_1^2+b_2^2-a_2^2+...+b_n^2-a_n^2)/2
(b1−a1)×r1+(b2−a2)×r2+...+(bn−an)×rn=(b12−a12+b22−a22+...+bn2−an2)/2
(
c
1
−
b
1
)
×
r
1
+
(
c
2
−
b
2
)
×
r
2
+
.
.
.
+
(
c
n
−
b
n
)
×
r
n
=
(
c
1
2
−
b
1
2
+
c
2
2
−
b
2
2
+
.
.
.
+
c
n
2
−
b
n
2
)
/
2
(c_1-b_1)\times r_1+(c_2-b_2)\times r_2+...+(c_n-b_n)\times r_n=(c_1^2-b_1^2+c_2^2-b_2^2+...+c_n^2-b_n^2)/2
(c1−b1)×r1+(c2−b2)×r2+...+(cn−bn)×rn=(c12−b12+c22−b22+...+cn2−bn2)/2
.
.
.
(
k
1
−
j
1
)
×
r
1
+
(
k
2
−
j
2
)
×
r
2
+
.
.
.
+
(
k
n
−
j
n
)
×
r
n
=
(
k
1
2
−
j
1
2
+
k
2
2
−
j
2
2
+
.
.
.
+
k
n
2
−
j
n
2
)
/
2
(k_1-j_1)\times r_1+(k_2-j_2)\times r_2+...+(k_n-j_n)\times r_n=(k_1^2-j_1^2+k_2^2-j_2^2+...+k_n^2-j_n^2)/2
(k1−j1)×r1+(k2−j2)×r2+...+(kn−jn)×rn=(k12−j12+k22−j22+...+kn2−jn2)/2
最后解方程即可!
代码:
#include<bits/stdc++.h>
using namespace std;
const double EPS=1e-7;
int n;
double point[20][20];
double mapp[15][15];
bool compare(double x,double y){
if(fabs(x)-fabs(y)>EPS) return 1;
return 0;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n+1;i++)
for(int j=1;j<=n;j++)
scanf("%lf",&point[i][j]);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
mapp[i][j]=point[i+1][j]-point[i][j];
mapp[i][n+1]=mapp[i][n+1]-point[i][j]*point[i][j]+point[i+1][j]*point[i+1][j];
}
mapp[i][n+1]/=2.0;
}
for(int i=1;i<=n;i++){
int u=i;
for(int j=i+1;j<=n;j++)
if(!compare(mapp[u][i],mapp[j][i]))
u=j;
if(u!=i) swap(mapp[u],mapp[i]);
for(int j=1;j<=n;j++){
if(i==j) continue;
double div=mapp[j][i]/mapp[i][i];
for(int k=i+1;k<=n+1;k++)
mapp[j][k]-=mapp[i][k]*div;
}
}
for(int i=1;i<=n;i++)
printf("%0.3lf ",mapp[i][n+1]/mapp[i][i]);
return 0;
}
T4 P5027 Barracuda
(P5027 Barracuda)
题目背景
小正方形的冒险旅途,并不顺利。
一路上,小正方形看到了壮美秀丽的小岛被污染,看到了雄伟壮观的火山,还碰到了许许多多的敌人。
眼下,小正方形正在对付一个巨大的三角形。
题目描述
大三角形给小正方形讲起自己的过去:过去的它是一个挖宝工,后来被黑暗之主污染才会落到此番境地。
它也希望小正方形去战胜黑暗之主,不过限于黑暗之主的眼线密布,因此必须给小正方形设置障碍才能骗过那些“眼线”。
他给小正方形的问题是:它有
n
n
n 个小三角形,每个小三角形有一定的质量,它对这些三角形进行了
n
+
1
n+1
n+1 次称量,然而由于托盘天平(
?
?
?)的问题,有一次称量的结果是有误的。
现在,大三角形想要知道最重的小三角形的 编号。
一组输入是合法的,当且仅当输入满足以下条件:
不存在一组
i
,
j
i,j
i,j,使得当我们假定第 ii 条称量数据有误时能求出一种合法方案且我们假定第
j
j
j 条称量数据有误时也能求出一种合法方案。
合法方案定义如下:
1、最重的三角形只有一个。
2、不存在重量不确定的三角形。
3、所有三角形的重量均为正整数。
输入格式
输入的第一行为一个正整数
n
n
n,表示小三角形的数目。
接下来
n
+
1
n+1
n+1 行,每行按照以下格式输入:
首先是一个正整数
m
m
m,表示这次称量抓了几个小三角形。
接下来
m
m
m 个整数,表示称量的小三角形的编号。
最后一个整数
w
e
i
g
h
t
weight
weight ,表示这次称量的结果。
输出格式
若合法,输出最重小三角形的编号,否则输出
"
i
l
l
e
g
a
l
"
"illegal"
"illegal"(不含引号)。
输入输出样例
输入
2
1 1 2
2 1 2 5
2 1 2 1
输出
2
输入
2
1 1 2
2 1 2 4
2 1 2 5
输出
2
输入
2
1 1 2
2 1 2 6
2 1 2 5
输出
illegal
说明/提示
样例一:
若第一次称量结果错误,则无法得出正确解。
若第二次称量结果错误,则第二个小三角形重量为负,显然不对。
若第三次称量结果错误,我们得出
1
1
1 号小三角形重量为
2
2
2,
2
2
2号小三角形重量为
3
3
3,
2
2
2号小三角形最重。
对于 100% 的数据, 1 ≤ m ≤ n ≤ 100 1 \leq m \leq n \leq 100 1≤m≤n≤100
思路:
发现数据
O
(
n
4
)
O(n^4)
O(n4)可过,于是暴力枚举错误数据,高斯消元后判断。
(模板别错)
代码:
#include<bits/stdc++.h>
using namespace std;
const double EPS=1e-5;
int n;
int mapp[150][150];
double p[150][150];
int wig[150];
int ans=-1;
bool bz=0;
inline void doit(){
for(int i=1;i<=n;i++){
int u=i;
for(int j=i+1;j<=n;j++)
if(fabs(p[j][i])>fabs(p[u][i])) u=j;
if(u!=i) swap(p[i],p[u]);
for(int j=1;j<=n;j++){
if(i==j) continue;
double div=p[j][i]/p[i][i];
for(int k=i+1;k<=n+1;k++)
p[j][k]-=p[i][k]*div;
}
}
for(int i=1;i<=n;i++){
if(fabs(p[i][n+1]/p[i][i]-floor(p[i][n+1]/p[i][i]))>EPS) return;
if(fabs((int)(p[i][n+1]/p[i][i]))<EPS){
wig[i]=0;
continue;
}
if((int)(p[i][n+1]/p[i][i])<0) return;
wig[i]=(int)(p[i][n+1]/p[i][i]);
}
int maxx=-1,sum=0,res=-1;
for(int i=1;i<=n;i++){
if(wig[i]>maxx){
res=i;
maxx=wig[i];
sum=0;
}
if(wig[i]==maxx) sum++;
if(wig[i]<0) return;
}
if(sum>1) return;
if(ans!=-1){
printf("illegal");
bz=1;
return;
}
ans=res;
return;
}
signed main(){
scanf("%d",&n);
for(int i=1;i<=n+1;i++){
int m;
scanf("%d",&m);
for(int j=1;j<=m;j++){
int x;
scanf("%d",&x);
mapp[i][x]=1;
}
int w;
scanf("%d",&w);
mapp[i][n+1]=w;
}
for(int i=1;i<=n+1;i++){
for(int j=1;j<=n+1;j++)
for(int k=1;k<=n+1;k++){
if(j<i) p[j][k]=(double)mapp[j][k];
if(j>=i) p[j][k]=(double)mapp[j+1][k];
}
doit();
if(bz) return 0;
}
if(ans==-1){
printf("illegal");
return 0;
}
printf("%d",ans);
return 0;
}