bzoj 3270 博物馆

题目大意

给你一个图
每个时刻一个人p[i]的概率不懂
1-p[i]的概率动
动的话等概率的走其中一条边
求两个人一个一开始在S,另一个一开始在T,
求对于每个点i,他们在i,i相遇的概率

分析

大致同bzoj 3143
定义二元组\((x,y)\)表示第一个人在x,第二个人在y的状态
可以把这些二元组状态看成一些点
对每个点定义\(E[i]\)
表示点i的期望经过次数
考虑它可以从什么状态转移过来
要么都不动,要么都动,要么一个动一个不动
注意的是碰面后不能再分离然后又碰面这样
所以对于二元组\((i,i)\),我们把它视为一个结束节点
另外对于二元组\((S,T)\),我们把它视为一个起始节点
还有要注意\(E[起始点]\)的期望式为其它点转移到它的期望再\(+1\),因为每种走法都会经过起点一次
为什么\(E(结束点)=P(结束点)\)呢?
因为是结束节点,到了它之后就不能再走了,经过次数只会为1
根据期望表达式\(E=\sum_{step}step*P(step)\)
该点概率就是\(P(step=1)=E\)

solution

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
typedef long double db;
const int M=407;

inline int rd(){
	int x=0;bool f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
	for(;isdigit(c);c=getchar()) x=x*10+c-48;
	return f?x:-x;
}

int n,m,nn;
int S,T;
int du[M];
db p[M];

int id(int x,int y){
	return (x-1)*n+y;
}

struct Guass{
	db a[M][M];
	db res[M];
	int n,m;
	void init(int sz){
		n=sz;
		m=sz+1;
		memset(a,0,sizeof(a));
		memset(res,0,sizeof(res));
	}
	void xiao(int x,db ff,int y){
		for(int i=1;i<=m;i++) a[y][i]-=a[x][i]*ff;
	}
	void getres(){
		int i,j;
		db tp;
		res[m]=1;
		for(i=n;i>0;i--){
			tp=0;
			for(j=i+1;j<=m;j++) tp+=a[i][j]*res[j];
			res[i]=(-tp)/a[i][i];
		}
		res[m]=0;
	}
	void gauss(){
		int i,j;
		for(i=1;i<m;i++){
			for(j=i;j<=n;j++)
			if(a[j][i]){
				swap(a[j],a[i]);
				break;
			}
			for(j=1;j<=n;j++)
			if(a[j][i]&&j!=i) xiao(i,a[j][i]/a[i][i],j);
		}
		getres();
	}
}GS;

vector<int>g[M];

int main(){
	n=rd(),m=rd();
	S=rd(),T=rd();

	int i,j,x,y,nw,to;

	for(i=1;i<=m;i++){
		x=rd(),y=rd();
		du[x]++; du[y]++;
		g[x].push_back(y);
		g[y].push_back(x);
	}

	for(i=1;i<=n;i++) scanf("%Lf",p+i);

	nn=n*n;
	GS.init(nn);
	for(i=1;i<=n;i++)
	for(j=1;j<=n;j++){
		nw=id(i,j);
		for(x=1;x<=g[i].size();x++)
		for(y=1;y<=g[j].size();y++){
			to=id(g[i][x-1],g[j][y-1]);
			GS.a[to][nw]+=(1-p[i])/du[i]*(1-p[j])/du[j];
		}
		for(x=1;x<=g[i].size();x++){
			to=id(g[i][x-1],j);
			GS.a[to][nw]+=(1-p[i])/du[i]*p[j];
		}
		for(y=1;y<=g[j].size();y++){
			to=id(i,g[j][y-1]);
			GS.a[to][nw]+=p[i]*(1-p[j])/du[j];
		}
		GS.a[nw][nw]+=p[i]*p[j];
	}
	nw=id(S,T);
	GS.a[nw][nn+1]+=1.0;
	for(i=1;i<=n;i++)
	for(nw=1;nw<=nn;nw++)GS.a[nw][id(i,i)]=0;//碰面后就不能再找一次了
	for(i=1;i<=nn;i++) GS.a[i][i]-=1.0;
	
	GS.gauss();
	
	for(i=1;i<=n;i++) printf("%Lf ",GS.res[id(i,i)]);

	return 0;
}
posted @ 2017-02-20 20:00  _zwl  阅读(105)  评论(0编辑  收藏  举报