您的位置:首页 > 其它

数学专题训练4

2014-03-02 21:19 169 查看
这次是矩阵与行列式

题目一:bzoj1013

我看到这题时反正没什么感觉。。。

其实对于球来说。。其上每一个点到球心的距离都是相等的。。。于是就可以根据这个来列方程

设球心为(x1,x2,...)对于点(a1,a2,...),(b1,b2,...) 有Σ(ai-xi)^2=Σ(bi-xi)^2

看起来很麻烦。。因为方程有二次项

但其实这个式子是可以打开的。。。打开后变成Σ2*(bi-ai)xi = Σbi^2-Σai^2 二次项被消掉了,直接就是线性方程(我当时居然觉得ai^2这些是二次项没消掉纠结了半天,真是太傻×了)

然后确定一个点出来。。其他所有点都与这个点一起建立一个线性方程,组成线性方程组。。。

然后直接高斯消元就搞定了...

#include<cstdlib>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int n;
double A[10+5][10+5];
double zb[10+5][10+5],fsum=0;
void gauss()
{
for(int i=1;i<=n;i++)
{
int maxt=i;
for(int j=i+1;j<=n;j++)
{
if(fabs(A[j][1])>fabs(A[maxt][1]))maxt=j;
}
if(maxt!=i)for(int j=1;j<=n+1;j++)swap(A[i][j],A[maxt][j]);
for(int j=i+1;j<=n;j++)
{
for(int k=n+1;k>=i;k--)A[j][k]-=A[i][k]*A[j][i]/A[i][i];
}
}
for(int i=n;i>=1;i--)
{
for(int j=i+1;j<=n;j++)A[i][n+1]-=A[i][j]*A[j][n+1];
A[i][n+1]/=A[i][i];
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf",&zb[0][i]);
fsum=fsum+zb[0][i]*zb[0][i];
}
for(int i=1;i<=n;i++)
{
double suma=0;
for(int j=1;j<=n;j++)
{
scanf("%lf",&zb[i][j]);
suma+=zb[i][j]*zb[i][j];
A[i][j]=2*(zb[i][j]-zb[0][j]);
}
A[i][n+1]=suma-fsum;
}
gauss();
for(int i=1;i<n;i++)printf("%.3f ",A[i][n+1]);
printf("%.3f\n",A
[n+1]);
return 0;
}


题目二:LA3704

这个题嘛。。。线性递推关系。。。一看就是矩阵乘法优化

设 矩阵v[t+1]=A*v[t],然后v[k]就等于 A^k *v[0]

但是仔细分析下矩阵乘法优化后的复杂度为 O(n^3logk),还是T得比较爽

这里要用到一个性质:A这个矩阵是一个循环矩阵(下一行由上一行依次移动以为得到)

而两个循环矩阵的乘积依旧是循环矩阵 。。所以我们在求A^k时,只计算和保存第一行就行了。。。

所以求A^k这个过程的复杂度就变成了 O(n^2logk).

至于矩阵怎么设计。。。应该不是很难的问题,实在解决不了的话可以给我留言。。我在这几个月会几乎天天都会来的

#include<cstdlib>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m,d,k;
int M[500+10][1];
int ele[500+10];
int temp[500+10];
int temp2[500+10];
int temp4[500+10];
int temp3[500+10][1];
void mul2(int a[],int b[][1])
{
memcpy(temp3,b,sizeof(temp3));
memset(b,0,sizeof(temp3));
for(int i=0;i<n;i++)
{
for(int k=0;k<n;k++)b[i][0]=(b[i][0]+((long long)a[((k-i)%n+n)%n]*temp3[k][0])%m)%m;
}
}
void mul(int a[],int b[])
{
memcpy(temp2,a,sizeof(temp2));
memcpy(temp4,b,sizeof(temp4));
memset(a,0,sizeof(temp));
for(int i=0;i<n;i++)
{
for(int k=0;k<n;k++)a[i]=(a[i]+((long long)temp2[k]*temp4[((i-k)%n+n)%n])%m)%m;
}
}
void qpow(int x)
{
memcpy(temp,ele,sizeof(temp));
memset(ele,0,sizeof(ele));
ele[0]=1;
while(x)
{
if(x&1)mul(ele,temp);
mul(temp,temp);
x>>=1;
}
}
int main()
{
while(scanf("%d%d%d%d",&n,&m,&d,&k)!=EOF)
{
for(int i=0;i<n;i++)
{
scanf("%d",&M[i][0]);
}
for(int i=0;i<n;i++)
{
if(i-0<=d||n-i<=d)ele[i]=1;
}
qpow(k);
mul2(ele,M);
for(int i=0;i<n-1;i++)printf("%d ",M[i][0]);
printf("%d\n",M[n-1][0]);
memset(M,0,sizeof(M));
memset(temp,0,sizeof(temp));
memset(temp4,0,sizeof(temp4));
memset(temp2,0,sizeof(temp2));
memset(temp3,0,sizeof(temp3));
memset(ele,0,sizeof(ele));
}
return 0;
}


题目三:Uva 10828

这道题有点高端。。期望+线性方程组

假设点i的期望执行次数为xi

那么xi=xa/da+xb/db+xc/dc+..(a,b,c为xi的前驱节点,di为点i的出度,意思就是:i点的期望执行次数=从a点走过来的概率*a点的期望执行次数+...)

例外是x1=xa/da+xb/db+xc/dc+..+1(因为他一开始会执行一次。。相当于有一个0号节点做前驱)

列出方程组然后消元。。。貌似解决了

但是没有。。。因为有的点不会被执行。。有的点会被无限执行(比如自环),在方程组中体现为多余方程或者矛盾方程

高斯消元有回带过程。。这里不知道的量就没法回带了

所以直接用高斯约当消元。。。不用回带

最后剩下的方程如果是矛盾的则说明所对应的这个变量为inf,如果是多余方程的话就是所对应的节点不会被执行(这句话是我自己的理解。。。没有太细想,可能不太对)

白书上是这么说的:当A[i][i]=A[i]
=0时 即方程为 xi*0=0时 xi为0 ,当A[i][i]=0&&A[i]
>0 即方程为xi*0=s(s>0)时xi为inf。。。除此因为有无穷大的变量而不能找出解的方程对应的xi也是无穷大(我认为是由于可以从 inf节点 走来。。。但好像不太解释得通,求大牛指导!)

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const double eps=1e-8;
int n;
bool w[100+10][100+10];
int du[100+10];
double A[100+10][100+10];
bool inf[100+10];
void gauss_jordan()
{
for(int i=1;i<=n;i++)
{
int maxt=i;
for(int j=i+1;j<=n;j++)
{
if(fabs(A[j][i])>fabs(A[maxt][i]))maxt=j;
}
if(abs(A[maxt][i])<eps)continue;
if(i!=maxt)for(int j=1;j<=n+1;j++)swap(A[i][j],A[maxt][j]);
for(int j=1;j<=n;j++)
{
if(i!=j)
{
for(int k=n+1;k>=i;k--)
{
A[j][k]-=A[j][i]/A[i][i]*A[i][k];
}
}
}
}
}
int main()
{
int cas=0;
while(scanf("%d",&n)!=EOF)
{
if(n==0)break;
memset(w,0,sizeof(w));
memset(du,0,sizeof(du));
memset(A,0,sizeof(A));
memset(inf,0,sizeof(inf));
cas++;
int a,b;
while(scanf("%d%d",&a,&b)!=EOF)
{
if(a==0&&b==0)break;
w[a][b]=1;
du[a]++;
}
A[1][n+1]=1;
for(int i=1;i<=n;i++)
{
A[i][i]=1;
for(int j=1;j<=n;j++)
{
if(w[j][i])
A[i][j]-=1.0/du[j];
}
}
gauss_jordan();
for(int i=n;i>=1;i--)
{
if(fabs(A[i][i])<eps&&fabs(A[i][n+1])>eps)inf[i]=true;
for(int j=i+1;j<=n;j++)
{
if(fabs(A[i][j])>eps&&inf[j])inf[i]=true;
}
}
printf("Case #%d:\n",cas);
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int u;
scanf("%d",&u);
if(inf[u])printf("infinity\n");
else printf("%.3f\n",fabs(A[u][u])<eps?0.0:A[u][n+1]/A[u][u]);
}
}
return 0;
}


题目四:Uva11542

这个我也比较晕。。。就说一句:异或方程组的消元过程进行几行 大概就是 确定了多少个未知数吧(说错了不要打我)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: