luogu P3232 [HNOI2013]游走
作者:互联网
题面传送门
真是我学习高斯消元以来的做过最正经的一道题目。
编号这个东西不太好做,但是我们如果把每条边经过的次数算出来然后排序后赋权就可以达到最小。
所以是算每条边出现的期望次数。
然后因为\(m\)太大实在不好弄,但是因为是随机跑的所以只要找到两端点出现次数然后除以度数加起来即可。
显然可以建立方程,然后高斯消元解出来即可。
时间复杂度\(O(n^3)\)
code:
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define l(x) x<<1
#define r(x) x<<1|1
#define re register
#define ll long long
#define db double
#define S 10000000
#define N 500
#define eps (1e-6)
#define mod 1000000007
using namespace std;
int n,m,in[N+5],x[N*N+5],y[N*N+5],now;double p[N+5][N+5],ans[N+5],pus,z[N*N+5];
struct yyy{int to,z;}tmp;
struct ljb{
int head,h[N+5];yyy f[N*N+5<<1];
I void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}
}s;
I void swap(db &x,db &y){db z=x;x=y;y=z;}
int main(){
freopen("1.in","r",stdin);
re int i,j,k;scanf("%d%d",&n,&m);
for(i=1;i<=m;i++) scanf("%d%d",&x[i],&y[i]),in[x[i]]++,in[y[i]]++,s.add(x[i],y[i]),s.add(y[i],x[i]);
for(i=1;i<n;i++) {
for(int j=s.h[i];j;j=tmp.z) tmp=s.f[j],p[i][tmp.to]=1.0/in[tmp.to];i==1&&(p[1][n+1]=-1);p[i][i]=-1;
}
for(i=1;i<n;i++){
for(now=i,j=i+1;j<=n+1;j++)p[j][i]>p[now][i]&&p[j][i]&&(now=j);
for(j=1;j<=n+1;j++) swap(p[i][j],p[now][j]);
for(pus=p[i][i],j=i;j<=n+1;j++) p[i][j]/=pus;
for(j=i+1;j<=n;j++){
for(pus=p[j][i],k=i;k<=n+1;k++) p[j][k]-=pus*p[i][k];
}
}
for(ans[n]=p[n][n+1],i=n-1;i;i--){
ans[i]=p[i][n+1];for(j=i+1;j<=n;j++) ans[i]-=ans[j]*p[i][j];
}
for(i=1;i<=m;i++) z[i]=ans[x[i]]/in[x[i]]+ans[y[i]]/in[y[i]];sort(z+1,z+m+1);
for(pus=0,i=1;i<=m;i++) pus+=z[i]*(m-i+1);printf("%.3lf\n",pus);
}
标签:now,luogu,HNOI2013,P3232,&&,条边,include,高斯消,define 来源: https://www.cnblogs.com/275307894a/p/14772349.html