BZOJ3143: [Hnoi2013] walk (expected DP Gauss elimination)

Keywords: C++

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 3597  Solved: 1618
[Submit][Status][Discuss]

Description

An undirected connected graph with vertices numbered from 1 to N and edges numbered from 1 to M.  
Small Z walks randomly on the graph. At the beginning, small Z is at vertex 1. In each step, small Z randomly selects an edge of the current vertex with equal probability, walks along this edge to the next vertex, and obtains a fraction equal to the number of this edge. When small Z reaches the N vertex, the walk ends, and the total score is the sum of all the scores obtained.  
Now, please number the M-edges to minimize the expected total score of small Z.

Input

The first row is a positive integer N and M, respectively, representing the number of vertices and edges of the graph. Next, each row of row M is an integer u,v(1 ≤ u,v ≤ N), indicating that there is an edge between vertex u and vertex v. The input ensures that 30% of the data satisfies N ≤ 10100% of the data satisfies 2 ≤ N ≤ 500 and is a simple undirected connected graph.

Output

Contains only one real number, representing the minimum expected value, with 3 decimal places reserved.

Sample Input

3 3
2 3
1 2
1 3

Sample Output

3.333

HINT

 

Edge (1,2) is numbered 1, edge (1,3) is numbered 2, and edge (2,3) is numbered 3.

 

Source

Unofficial data

 
This question is disgusting..
The idea is to first express the probability of the edge, then the probability of the point
The probability of finding points can't be dealt with directly
And then Gauss elimination
At last, the greedy edge is added. Obviously, the smaller the probability is, the larger the number should be
Here's a more detailed explanation
https://www.luogu.org/problemnew/solution/P3232
 
#include<cstdio>
#include<cstring>
#include<algorithm>
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?EOF:*p1++)
using namespace std;
const int MAXN=1e6+10;
const double eps=1e-7;
char buf[1<<23],*p1=buf,*p2=buf;
inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int N,M;
struct node
{
    int u,v,nxt;
}edge[MAXN];
int head[MAXN],num=1;
inline void AddEdge(int x,int y)
{
    edge[num].u=x;
    edge[num].v=y;
    edge[num].nxt=head[x];
    head[x]=num++;
}
double f[1001][1001],ans[MAXN],E[MAXN],inder[MAXN];
int S[MAXN],T[MAXN];
int dcmp(double x)
{
    if(x<eps&&x>-eps) return 0;
    else return x<0?-1:1;
}
void Gauss()
{

    for(int i=1;i<N;i++)
    {
        int mx=i;
        for(int j=i+1;j<N;j++)
            if( dcmp(f[j][i]-f[mx][i])>0 ) mx=j;
        if(mx!=i) swap(f[i],f[mx]);
        for(int j=i+1;j<N;j++)
        {
            double tmp=f[j][i]/f[i][i];
            for(int k=i;k<=N;k++)
                f[j][k]-=(double)tmp*f[i][k];
        }
    }
    for(int i=N-1;i>=1;i--)
    {
        for(int j=i+1;j<N;j++)
            f[i][N]-=ans[j]*f[i][j];
        ans[i]=f[i][N]/f[i][i];
    }
}
int main()
{
    #ifdef WIN32
    freopen("a.in","r",stdin);
    #else
    #endif
    memset(head,-1,sizeof(head));
    N=read(),M=read();
    for(int i=1;i<=M;i++)
    {
        int x=read(),y=read();
        AddEdge(x,y);AddEdge(y,x);
        inder[x]++;inder[y]++;
        S[i]=x;T[i]=y;
    }
    f[1][N]=1;
    for(int i=1;i<N;i++) f[i][i]=1;
    for(int i=1;i<N;i++)
        for(int j=head[i];j!=-1;j=edge[j].nxt)
            if(edge[j].v!=N)
                f[i][edge[j].v]=(double)-1.00/inder[edge[j].v];
    Gauss();
    for(int i=1;i<=M;i++) 
        E[i]=ans[S[i]]/inder[S[i]]+ans[T[i]]/inder[T[i]];
    sort(E+1,E+M+1);
    double out=0;
    for(int i=1;i<=M;i++)
        out+=E[i]*(M-i+1);
    printf("%.3lf",out);
    return 0;
}

 

Posted by cursed on Sat, 04 Apr 2020 15:45:37 -0700