• Luogu6030 SDOI2012 走迷宫


    Description

    link

    给定一个有向图,求从 (S) 走到 (T) 的期望步数

    如果没法走到(T),那么步数为 (inf)

    求期望步数

    (nle 10^4) 每个强连通分量的大小不超过 (100)

    Solution

    有向图,期望

    (tarjan) 和高斯消元呗

    我们先列个式子

    [f_i=1+frac{1}{d_i}sum_{(i,j)in E} f_j ]

    其中 (f_i) 表示从 (i)(T) 的期望步数

    我们发现这个直接上高斯消元是不大行的

    然后题目中:

    “每个强连通分量的大小不超过 (100)

    所以我们想到了对于每个强连通分量里面消元

    这样大概是个 (O(100^4)) 的复杂度,还跑不满

    考虑到 (tarjan) 出栈的有序性,我们从 (1)(n) 进行消元就 (Ok)

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    namespace yspm{
    	inline int read()
    	{
    		int res=0,f=1; char k;
    		while(!isdigit(k=getchar())) if(k=='-') f=-1;
    		while(isdigit(k)) res=res*10+k-'0',k=getchar(); 
    		return res*f;
    	}
    	const int N=1e4+10;
    	vector<int> g[N],scc[N];
    	int n,m,s,t;
    	int dfn[N],low[N],tim,st[N],top,vis[N],d[N],p[N],cnt,id[N];
    	double a[200][200],ans[N],f[N];
    	inline void tarjan(int x)
    	{
    		dfn[x]=low[x]=++tim; st[++top]=x; vis[x]=1;
    		int sz=g[x].size();
    		for(int i=0;i<sz;++i)
    		{
    			int t=g[x][i];
    			if(!dfn[t]) tarjan(t),low[x]=min(low[x],low[t]);
    			else if(vis[t]) low[x]=min(low[x],dfn[t]);
    		}
    		if(low[x]==dfn[x])
    		{
    			cnt++;
    			do{
    				id[st[top]]=cnt; 
    				vis[st[top]]=0; 
    				scc[cnt].push_back(st[top]);
    				p[st[top]]=scc[cnt].size();
    				top--;
    			}while(st[top+1]!=x);
    		} return ;
    	}
    	
    	inline void guass(int x)
    	{
    		for(int i=1;i<=x;++i) 
    		{
    			int t=i;
    			for(int j=i+1;j<=x;++j) if(fabs(a[j][i])>fabs(a[t][i])) t=j; 
    			if(i!=t) swap(a[i],a[t]);
    			if(fabs(a[i][i])==0) return ;
    			for(int j=i+1;j<=x;++j)
    			{
    				double d=a[j][i]/a[i][i]; 
    				for(int k=1;k<=x+1;++k) a[j][k]-=a[i][k]*d;
    			} 
    		}
    		for(int i=x;i>=1;--i)
    		{
    			for(int j=i+1;j<=x;++j) a[i][x+1]-=ans[j]*a[i][j];
    			ans[i]=a[i][x+1]/a[i][i];
    		}
    		return ;
    	}
    	signed main()
    	{
    		n=read(); m=read(); s=read(); t=read();
    		for(int i=1;i<=m;++i)
    		{
    			int x=read(),y=read(); d[x]++;
    			g[x].push_back(y); 
    		}
    		tarjan(s); if(!dfn[t]) return puts("INF"),0;
    		for(int i=1;i<=cnt;++i)
    		{
    			memset(a,0,sizeof(a)); 
    			memset(ans,0,sizeof(ans));
    			int sz=scc[i].size();
    			for(int j=0;j<sz;++j)
    			{
    				int now=scc[i][j];
    				if(now==t){a[p[now]][p[now]]=1; continue;}
    				a[p[now]][p[now]]=1; a[p[now]][sz+1]=1;
    				int siz=g[now].size(); 
    				for(int k=0;k<siz;++k)
    				{
    					int t=g[now][k];
    					if(id[t]==id[now]) a[p[now]][p[t]]-=1.0/d[now];
    					else a[p[now]][sz+1]+=f[t]/d[now];
    				}
    				if(!siz) a[p[now]][sz+1]=1e18;
    			}
    			guass(sz);
    			for(int j=0;j<sz;++j)
    			{
    				f[scc[i][j]]=ans[p[scc[i][j]]]; 
    				if(f[scc[i][j]]>1e10) f[scc[i][j]]=1e18;
    			}
    		}
    		if(f[s]>1e10) puts("INF");
    		else printf("%.3lf
    ",f[s]);
    		return 0;
    	}
    }
    signed main(){return yspm::main();}
    

    Review

    面向数据范围编程.jpg

    还有,如果明确高斯消元了,而且复杂度太大,那就根据题里的信息降复杂度

  • 相关阅读:
    JavaScript判断图片是否加载完成的三种方式 (转)
    支付宝异步通知notify_url接收不了问题解决(转)
    支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url
    Nginx Cache中$request_filename(转)
    win7下搭建nginx+php的开发环境(转)
    Nginx报出504 Gateway Timeout错误2
    BZOJ 3990 [SDOI 2015] 排序 解题报告
    BZOJ 3992 [SDOI 2015] 序列统计 解题报告
    BZOJ 3993 [SDOI 2015] 星际战争 解题报告
    BZOJ 3971 Матрёшка 解题报告
  • 原文地址:https://www.cnblogs.com/yspm/p/12898605.html
Copyright © 2020-2023  润新知