bzoj 3150: [Ctsc2013]猴子 高斯消元

        范围N<=100。

       显然我们可以令f[S]表示手上牌集合为S时的胜率,然后高斯消元或者多次迭代出解。

       然后打表发现若A∩B=∅,则f[A∪B]=f[A]+f[B],如果这个成立,那我们就可以令f[i]表示手上牌为i的胜率然后高斯消元辣~\(≧▽≦)/~。

       考虑另一个游戏:三个人a,b,c,手上的牌为A,B,C,然后任意选两张牌如果不在同一个人手中就和这道题目一样操作。那么显然有f[A]+f[B]+f[C]=1;考虑对a而言,b,c实际上是一个整体,这个整体的胜率f[B∪C]=1-f[A],就得到了f[B∪C]=f[B]+f[C](B∩C=∅)。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#define N 105
using namespace std;

int n,m; double a[N][N];
int main(){
	scanf("%d%d",&n,&m); int i,j,k; double tmp;
	for (i=1; i<n; i++){
		a[i][i]=1-n;
		for (j=1; j<=n; j++){
			scanf("%lf",&tmp);
			if (i!=j){ a[i][j]=tmp; a[i][i]+=tmp; }
		}
	}
	for (i=1; i<=n; i++){
		scanf("%lf",&tmp); a[n][i]=1;
	}
	a[n][n+1]=1;
	for (i=1; i<=n; i++){
		for (j=k=i; j<=n; j++)
			if (fabs(a[j][i])>fabs(a[k][i])) k=j;
		if (i!=k) swap(a[i],a[k]);
		for (j=i+1; j<=n; j++){
			tmp=a[j][i]/a[i][i];
			for (k=i; k<=n+1; k++) a[j][k]-=tmp*a[i][k];
		}
	}
	for (i=n; i; i--){
		for (j=i+1; j<=n; j++) a[i][n+1]-=a[i][j]*a[j][n+1];
		a[i][n+1]/=a[i][i];
	}
	char ch=getchar();
	while (m--){
		while (ch<'0' || ch>'1') ch=getchar();
		tmp=0;
		for (i=1; i<=n; i++,ch=getchar())
			if (ch=='1') tmp+=a[i][n+1];
		printf("%.8f\n",tmp);
	}
	return 0;
}


by lych

2016.5.24

你可能感兴趣的:(数学,高斯消元)