bzoj 3143 hnoi2013 游走(高斯消元)

这里写图片描述

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

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

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

最后贪心就好。

代码如下:

#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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值