• bzoj 3143 [Hnoi2013]游走


    题目大意

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

    分析

    直接搞边比较困难
    我们考虑到如果一条边期望经过次数多,就应该给它一个小的编号
    而一条边(x,y)期望经过次数就是(frac {e[x]} {du[x]}+frac {e[y]} {du[y]})
    e[x]用高斯消元求

    方法1

    设e[i]为i期望有多少次机会往旁边走
    注意到:走到n后无法走回来
    所以即使有连边i-n,i也无法从n转移过来
    (e[n]=0)
    (e[1]=(sum frac {e[y]} {du[y]} )+1)(每种方案一都多走一次)
    (e[x]=sum frac {e[y]} {du[y]} (x!=1))

    方法2

    设e[i]为i期望经过多少次
    注意到:走到n后无法走回来
    (e[n]=sum frac {e[y]} {du[y]}=1)
    (e[x]=sum frac {e[y]} {du[y]})
    最后算边的次数时注意不能从n走来

    solution1

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    typedef long double db;
    const int M=507;
    const db eps=1e-10;
    
    inline int rd(){
    	int x=0;bool f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    	for(;isdigit(c);c=getchar()) x=x*10+c-48;
    	return f?x:-x;
    }
    
    int n,m;
    int du[M];
    
    struct node{
    	int x,y;
    	db z;
    	node(int xx=0,int yy=0,db zz=0){
    		x=xx;
    		y=yy;
    	}
    }ed[M*M*2];
    
    struct Guass{
    	db a[M][M];
    	db res[M];
    	int n,m;
    	void init(int nn){
    		n=nn;
    		m=nn+1;
    		memset(res,0,sizeof(res));
    		memset(a,0,sizeof(a));
    	}
    	void xiao(int x,db ff,int y){
    		for(int i=1;i<=m;i++)
    			a[y][i]-=a[x][i]*ff;
    	}
    	void getres(){
    		int i,j;
    		db tp;
    		for(i=n;i>0;i--){
    			tp=0;
    			for(j=i+1;j<m;j++) tp+=a[i][j]*res[j];
    			res[i]=(-tp-a[i][m])/a[i][i];
    		}
    	}
    	void gauss(){
    		int i,j,k=0;
    		for(i=1;i<m;i++){
    			k++;
    			for(j=k;j<=n;j++)
    			if(fabs(a[j][i])>eps){
    				swap(a[j],a[k]);
    				break;
    			}
    			for(j=1;j<=n;j++)
    			if(fabs(a[j][i])>eps&&j!=k)
    				xiao(k,a[j][i]/a[k][i],j);
    		}
    		getres();
    	}
    }GS;
    
    bool cmpw(node x,node y){
    	return x.z>y.z;
    }
    
    int main(){
    
    	n=rd(),m=rd();
    	int i,x,y;
    	for(i=1;i<=m;i++){
    		x=rd(),y=rd();
    		du[x]++; du[y]++;
    		ed[i]=node(x,y);
    	}
    	GS.init(n);
    	for(i=1;i<=m;i++){
    		x=ed[i].x, y=ed[i].y;
    		if(x!=n) GS.a[x][y]+=1.0/du[y];
    		if(y!=n) GS.a[y][x]+=1.0/du[x];
    	}
    	for(i=1;i<=n;i++) GS.a[i][i]-=1.0;
    	GS.a[1][n+1]+=1.0;
    	GS.gauss();
    
    	for(i=1;i<=m;i++){
    		x=ed[i].x, y=ed[i].y;
    		ed[i].z=0;
    		ed[i].z+=GS.res[x]/du[x];
    		ed[i].z+=GS.res[y]/du[y];
    	}
    	
    	sort(ed+1,ed+m+1,cmpw);
    	db ans=0;
    	for(i=1;i<=m;i++) ans+=ed[i].z*i;
    
    	printf("%.3Lf",ans+eps);	
    
    	return 0;
    }
    

    solution2

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    typedef long double db;
    const int M=507;
    
    inline int rd(){
    	int x=0;bool f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    	for(;isdigit(c);c=getchar()) x=x*10+c-48;
    	return f?x:-x;
    }
    
    int n,m;
    int du[M];
    
    struct node{
    	int x,y;
    	db z;
    	node(int xx=0,int yy=0,db zz=0){
    		x=xx;
    		y=yy;
    	}
    }ed[M*M*2];
    
    struct Gauss{
    	db a[M][M];
    	db res[M];
    	int n,m;
    	void init(int nn){
    		n=nn;
    		m=nn+1;
    		memset(res,0,sizeof(res));
    		memset(a,0,sizeof(a));
    	}
    	void xiao(int x,db ff,int y){
    		for(int i=1;i<=m;i++)
    			a[y][i]-=a[x][i]*ff;
    	}
    	void getres(){
    		int i,j;
    		db tp;
    		res[m]=1;
    		for(i=n;i>0;i--){
    			tp=0;
    			for(j=i+1;j<=m;j++) tp+=a[i][j]*res[j];
    			res[i]=-tp/a[i][i];
    		}
    		res[m]=0;//****
    	}
    	void gauss(){
    		int i,j,k=0;
    		for(i=1;i<m;i++){
    			k++;
    			for(j=k;j<=n;j++)
    			if(a[j][i]){
    				swap(a[j],a[k]);
    				break;
    			}
    			for(j=1;j<=n;j++)
    			if(a[j][i]&&j!=k)
    				xiao(k,a[j][i]/a[k][i],j);
    		}
    		getres();
    	}
    }GS;
    
    bool cmpw(node x,node y){
    	return x.z>y.z;
    }
    
    int main(){
    	
    	n=rd(),m=rd();
    	int i,x,y;
    	for(i=1;i<=m;i++){
    		x=rd(),y=rd();
    		du[x]++; du[y]++;
    		ed[i]=node(x,y);
    	}
    	GS.init(n-1);//只用解1...n-1,下面的代码中-1都只是将第一条方程去掉后每条方程往上移一下而已
    	for(i=1;i<=m;i++){
    		x=ed[i].x, y=ed[i].y;
    		if(y!=n) GS.a[x-1][y]+=1.0/du[y];
    		if(x!=n) GS.a[y-1][x]+=1.0/du[x];
    	}
    	for(i=2;i<n;i++) GS.a[i-1][i]-=1.0;
    	GS.a[n-1][n]-=1.0;//第n项为常数项 
    	GS.gauss();
    	GS.res[n]=0;
    	
    	for(i=1;i<=m;i++){
    		x=ed[i].x, y=ed[i].y;
    		ed[i].z=0;
    		ed[i].z+=GS.res[x]/du[x];
    		ed[i].z+=GS.res[y]/du[y];
    	}
    	
    	sort(ed+1,ed+m+1,cmpw);
    	db ans=0;
    	for(i=1;i<=m;i++) ans+=ed[i].z*i;
    
    	printf("%.3Lf
    ",ans);	
    
    	return 0;
    }
    
  • 相关阅读:
    [附件解决方案]CruiseControl.NET 超冷门”BUG” 关键字:VstsHistoryParser ParseChangeSet CheckForModifications FormatException
    SQL SERVER 2008 函数大全 字符串函数
    第五章 DOM接口 DOM Interfaces
    [MSSQL]FOR XML AUTO I
    DOS CHOICE命令
    [MSSQL]NTILE另类分页有么有?!
    原生态webglDEMO,以后可能选择Three.JS来代替了,代码网上找的,参考引用
    [MSSQL]COALESCE与ISNULL函数
    【转】“无法在Web服务器上启动调试。您不具备调试此应用程序的权限,此项目的URL位于Internet区域”错误提示的解决
    【转】一个项目涉及到的50个Sql语句(整理版)
  • 原文地址:https://www.cnblogs.com/acha/p/6419890.html
Copyright © 2020-2023  润新知