题目传送门
题意:
一个无向连通图,顶点从1编号到N,边从1编号到M。
小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。
现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。
思路:很显然,我们肯定希望经过次数最多的边的标号最小,但是由于边的数量可能很多,而且好像也不存在什么很好转移的东西,那么我们就需要考虑点。
假设E[X]代表从x这个点出发的次数,那么对于{u,v}这样一条边的被经过的次数显然等于$\frac{E[u]}{deg[u]}+\frac{E[v]}{deg[v]}$ deg代表度数,也就是从其他点过来的概率。所以我们只要算出E[x]就可以完成这道题了。
我们考虑一般的u(除了起点和终点),显然易得$E[X]=\sum \frac {f[v]}{deg[v]}$。
而终点就是的E[X]就是0,起点的期望,除了上述的式子,还需要加入最初始的1.(游戏开局),由于我们这样可以得到n个式子,而且n个式子之间存在推来推去的关系,显然可以考虑高斯消元。
所以就按照上面这个式子高斯消元求解,然后把边按经过次数排序就是答案了。
#pragma GCC optimize (2) #pragma G++ optimize (2) #pragma comment(linker, "/STACK:102400000,102400000") #include#define rep(i,a,b) for(int i=a;i<=b;i++) #define dep(i,b,a) for(int i=b;i>=a;i--) #define clr(a,b) memset(a,b,sizeof(a)) #define pb push_back #define pii pair using namespace std; typedef long long ll; ll rd() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=510; const int inf=0x3f3f3f3f; int T,n,m; vector<int >ve[maxn]; struct edge{ int u,v; double g; friend bool operator<(const edge &a,const edge &b){ return a.g>b.g; } }e[maxn*maxn]; const double eps=1e-12; int equ=500,var=500; double a[maxn][maxn],x[maxn],deg[maxn]; int Gauss()//高斯消元 返回 0 无解 返回 1有解 { int i,j,k,col,max_r; for(k=0,col=0;k var;k++,col++) { max_r=k; for(i=k+1;i ) if(fabs(a[max_r][col])>fabs(a[max_r][col])) max_r=i; if(fabs(a[max_r][col]) return 0; if(k!=max_r) { for(j=col;j<var;j++) swap(a[k][j],a[max_r][j]); swap(x[k],x[max_r]); } x[k]/=a[k][col]; for(j=col+1;j<var;j++) a[k][j]/=a[k][col]; a[k][col]=1; for(i=0;i ) { if(i!=k) { x[i]-=x[k]*a[i][col]; for(j=col+1;j<var;j++) a[i][j]-=a[k][j]*a[i][col]; a[i][col]=0; } } } return 1; } int main(){ cin>>n>>m; rep(i,1,m){ scanf("%d%d",&e[i].u,&e[i].v); deg[e[i].u]++; deg[e[i].v]++; ve[e[i].u].push_back(e[i].v); ve[e[i].v].push_back(e[i].u); } x[0]=1; a[n-1][n-1]=1; equ=var=n+1; rep(i,1,n-1){ a[i-1][i-1]=1; //for(auto &v:ve[i]){ for(int j=0;j ){ int v=ve[i][j]; if(v!=n) a[i-1][v-1]=-1/deg[v]; } } Gauss(); for(int i=1;i<=m;i++){ e[i].g=0; if(e[i].u!=n) e[i].g+=x[e[i].u-1]/deg[e[i].u]; if(e[i].v!=n) e[i].g+=x[e[i].v-1]/deg[e[i].v]; } sort(e+1,e+1+m); double ans=0; rep(i,1,m){ ans+=i*e[i].g; } printf("%.3f\n",ans); }