bzoj 3143 hnoi2013 游走(高斯消元)

来源:互联网 发布:域名卖到国外 编辑:程序博客网 时间:2024/05/16 14:12

这里写图片描述

这道题说是一道概率题但这种概率实际上就是一道高斯消元。

每个点到的概率等于所以与他相连的点的概率除以相应的边数,构造出来就是个方程组,高斯消元解一波,然后每个点的可能性就是他所连的点的可能性除以边数相加。

高斯消元的解释(不会的可以去看看)

最后贪心就好。

代码如下:

#include<cstdlib>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>using namespace std;const int maxn=505;struct edge{    int x,y,id;    double sum;    friend bool operator <(edge a,edge b)    {        return a.sum-b.sum>0.000000001;    }}e[maxn*maxn];int n,m;double c[maxn][maxn]={0};int out[maxn]={0};bool vis[maxn][maxn]={0};double d[maxn];void gauss(){    int i=1,j=1;    while(i<=n&&j<=n)    {        int t=i;        for(int k=i+1;k<=n;k++) if(fabs(c[k][j])>fabs(c[t][j])) t=k;        if(fabs(c[t][j])>0)        {            if(t!=i)for(int k=j;k<=n+1;k++) swap(c[t][k],c[i][k]);            double tt;            for(int k=i+1;k<=n;k++) if(fabs(c[k][j]))            {                tt=c[k][j]/c[i][j];                for(int x=j;x<=n+1;x++)                c[k][x]-=c[i][x]*tt;            }            i++;        }        j++;    }    for(int i=n;i>=1;i--)    {        for(int j=i+1;j<=n+1;j++)        c[i][n+1]-=c[i][j]*c[j][n+1];        c[i][n+1]/=c[i][i];     }}void init(){    scanf("%d%d",&n,&m);    int x,y;    for(int i=1;i<=m;i++)    {        scanf("%d%d",&e[i].x,&e[i].y);        vis[e[i].x][e[i].y]=vis[e[i].y][e[i].x]=1;        out[e[i].x]++,out[e[i].y]++;    }    n--;    for(int i=1;i<=n;i++) c[i][i]=-1;    for(int i=1;i<=n;i++)    for(int j=1;j<=n;j++) if(vis[i][j])    c[i][j]=1.0/(double)out[j];    c[1][n+1]=-1;    gauss();}int main(){    freopen("in.txt","r",stdin);    init();    for(int i=1;i<=m;i++)    e[i].sum=c[e[i].x][n+1]/out[e[i].x]+c[e[i].y][n+1]/out[e[i].y];    sort(e+1,e+1+m);    double ans=0;    for(int i=1;i<=m;i++)    ans+=e[i].sum*i;    printf("%.3lf",ans);    return 0;}
0 0
原创粉丝点击