其他分享
首页 > 其他分享> > bzoj3143 luogu3232 游走

bzoj3143 luogu3232 游走

作者:互联网

3143: [Hnoi2013]游走

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 4289  Solved: 2008
[Submit][Status][Discuss]

Description

一个无向连通图,顶点从1编号到N,边从1编号到M。 
小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。 
现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。

Input

第一行是正整数N和M,分别表示该图的顶点数 和边数,接下来M行每行是整数u,v(1≤u,v≤N),表示顶点u与顶点v之间存在一条边。 输入保证30%的数据满足N≤10,100%的数据满足2≤N≤500且是一个无向简单连通图。

Output

仅包含一个实数,表示最小的期望值,保留3位小数。

Sample Input

3 3
2 3
1 2
1 3

Sample Output

3.333

HINT

 

边(1,2)编号为1,边(1,3)编号2,边(2,3)编号为3。    
#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n,m;
int mp[N][N],deg[N];
double mt[N][N],dp[N];
struct edge
{
    int s,t;
}e[N*N];
void solve(int now)
{
    if(now==n) return;
    if(mt[now][now]==0)
    {
        for(int i=now+1;i<n;++i)
            if(mt[i][now]!=0)
            {
                for(int j=now;j<=n+1;++j)
                    swap(mt[now][j],mt[i][j]);
                break;
            }
    }
    for(int i=now+1;i<n;++i)
    {
        double tmp=-mt[i][now]/mt[now][now];
        for(int j=now;j<=n+1;++j)
            mt[i][j]+=tmp*mt[now][j];
    }
    //print();
    solve(now+1);
    dp[now]=mt[now][n+1]/mt[now][now];
    //cout<<dp[now]<<endl;
    for(int i=now-1;i>=1;--i) mt[i][n+1]-=dp[now]*mt[i][now];
}
bool cmp(edge u,edge v)
{
    return dp[u.s]+dp[u.t]>dp[v.s]+dp[v.t];
}
int main()
{
    int cnt=0;
    scanf("%d%d",&n,&m);
    memset(mp,-1,sizeof(mp));
    for(int i=1;i<=m;++i)
    {    
        int a,b;
        scanf("%d%d",&a,&b);
        e[i].s=a,e[i].t=b;
        mp[a][b]=mp[b][a]=1;
        ++deg[a],++deg[b];
    }
    mt[1][n+1]=-1.0;
    for(int i=1;i<n;++i)
        for(int j=1;j<=n;++j)
        {
            if(i==j) mt[i][i]=-1.0;
            if(mp[i][j]<0) continue;
            ++cnt;
            mt[i][j]=1.0/(double)deg[i];
        }
    //print();
    solve(1);
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;++i)
    {
        mp[e[i].s][e[i].t]=mp[e[i].t][e[i].s]=i;
    //    cout<<e[i].s<<" "<<e[i].t<<endl;
    }
    for(int i=1;i<n;++i)
        for(int j=1;j<=n+1;++j)
            mt[i][j]=0.0;
    for(int i=1;i<n;++i)
        for(int j=1;j<=n;++j)
        {
            if(i==j) mt[i][i]=-1.0;
            if(mp[i][j]<0) continue;
            ++cnt;
            mt[i][j]=1.0/(double)deg[i];
            mt[i][n+1]-=(double)mp[i][j]/deg[i];
        }
    solve(1);
    printf("%.3lf",dp[1]);
    return 0;
}

 

标签:mt,bzoj3143,编号,int,顶点,luogu3232,游走,now,dp
来源: https://www.cnblogs.com/w19567/p/11247449.html