codeforces 113D&bzoj 3270

来源:互联网 发布:网络热点视频 编辑:程序博客网 时间:2024/06/08 19:47

题目大意:

一张图,N(N<=22)个点M条无向边,有两个人分别在A点B点。

对于每个点,有Pi的几率留在原地,否则等概率的向相连的点走去。

问对于每个点,有多少的概率两个人在这个点相遇?

这题显然是概率型dp+高斯消元。但是要注意求方程组的方法。


一开始,我试图枚举x,用P[x][x]表示同时在x点相遇的概率,P[i][j]表示从i,j出发同时到达x点的概率。

然而这样似乎可以做,但是解N次N*N个点的方程组,复杂度是O(N^7),妥妥超时。(不过听说卡常能卡过去?雾)


然后发现完全没必要这样搞:

因为这个方程组是N*N元的,我们直接用F[id[i][j]]表示从A,B到达i,j的概率就好了=。=(我是撒币吗)

那么显然我们都得到每对i,j之间相互转化的概率,并建立N*N元方程组,直接高斯消元。

有些细节要注意下,参考了黄学长的博客(http://hzwer.com/),才想起来初始状态的概率值是要加一的。

附代码

#include<bits/stdc++.h>using namespace std;double a[600][600],p[25],du[25];int id[25][25],n,m,x,y,tot,st;int beg[600],to[600],nex[600],len=0;void add(int a,int b){beg[a]=++len;to[len]=b;nex[len]=beg[a];}void build(int x,int y){int bh=id[x][y];    a[bh][bh]=1.0;    for(int i=beg[x];i;i=nex[i])        for(int j=beg[y];j;j=nex[j]){if(to[i]==to[j]) continue;            int tmp=id[to[i]][to[j]];            double l,r;            if(to[i]==x) l=p[to[i]];else l=(1-p[to[i]])/du[to[i]];            if(to[j]==y) r=p[to[j]];else r=(1-p[to[j]])/du[to[j]];            a[bh][tmp]-=l*r;        }}int main(){    memset(beg,0,sizeof(beg));    scanf("%d%d%d%d",&n,&m,&x,&y);    for(int i=0,l,r;i<m;i++){        scanf("%d%d",&l,&r);        add(l,r);add(r,l);        du[l]++;du[r]++;    }for(int i=1;i<=n;i++) add(i,i);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)id[i][j]=++tot;a[id[x][y]][tot+1]=1;    for(int i=1;i<=n;i++)scanf("%lf",&p[i]);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)build(i,j);for(int i=1;i<=tot;i++){int tmp=i;while(!a[tmp][i]&&tmp<=tot) tmp++;if(tmp>tot) continue;for(int j=i;j<=tot+1;j++) swap(a[i][j],a[tmp][j]);for(int j=1;j<=tot;j++)if(j!=i){double t=a[j][i]/a[i][i];for(int k=1;k<=tot+1;k++)a[j][k]-=t*a[i][k];}}for(int i=1;i<=n;i++){int t=id[i][i];printf("%.6f ",a[t][tot+1]/a[t][t]);}printf("\n");return 0;}


原创粉丝点击