Description
Morenan被困在了一个迷宫里。迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T。可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的有向边,到达另一个点。这样,Morenan走的步数可能很长,也可能是无限,更可能到不了终点。若到不了终点,则步数视为无穷大。但你必须想方设法求出Morenan所走步数的期望值。
Input
第1行4个整数,N,M,S,T
第[2, M+1]行每行两个整数o1, o2,表示有一条从o1到o2的边。
Output
一个浮点数,保留小数点3位,为步数的期望值。若期望值为无穷大,则输出"INF"。
【样例输入1】
6 6 1 6
1 2
1 3
2 4
3 5
4 6
5 6
【样例输出1】
3.000
【样例输入2】
9 12 1 9
1 2
2 3
3 1
3 4
3 7
4 5
5 6
6 4
6 7
7 8
8 9
9 7
【样例输出2】
9.500
【样例输入3】
2 0 1 2
【样例输出3】
INF
【数据范围】
测试点
|
N
|
M
|
Hint
|
[1, 6]
|
<=10
|
<=100
|
|
[7, 12]
|
<=200
|
<=10000
|
|
[13, 20]
|
<=10000
|
<=1000000
|
保证强连通分量的大小不超过100
|
另外,均匀分布着40%的数据,图中没有环,也没有自环
首先考虑输出INF的情况。
明显只有s和t不能互相通达或者从s出发可能走到某个岔道之后无法走到t的时候输出INF。
然后是解决如何求s到t的期望步数。
这个明显可以列方程来解。
设点i的到达t的期望步数为ans[i],由定义可知ans[t]=t。
再设count[i]表是以i为起点的有向边的个数。
根据期望值的概念,ans[i]=sigma(ans[v]/count[i])+1 (存在边(i,v))
直接移项高斯消元搞好了。
这样可以通过60%的数据,而且对于大数据有两组INF的,可以得到70分。
大数据如何解决呢?
注意题中提示每个强连通分量大小不超过100,100这个数字是可以高斯消元的。
考虑强连通分量,很容易发现,如果没有环的话,可以按照拓扑序直接算,不需要列方程。
为什么需要列方程呢,因为存在环的话,方程前面自己本身的系数不为1。
什么项中会含有自己呢,只有跟自己在同一个强连通分量里的项。
所以可以把方程分成一个一个强连通分量来按拓扑序求。
这样时间上就可以通过了。
我的程序在本地测数据会有最后几个测试点会超过1s……总计时间6.8s左右……在bzoj上9.4s左右勉强跑完……
program bzoj2707;
const
eps=1e-7;
type
st=array [0..10001] of boolean;
ty1=array [0..10001] of longint;
ty2=array [0..1000001] of longint;
equation=array [0..201] of double;
var
n,m,s,t,i,j,k,u,v,tot,all:longint;
dd,dfn,low,stack,form,num,roo,root,beg:ty1;
ans:array [0..10001] of double;
pre,next,point,nex,poi:ty2;
o1,o2,fin,yes:st;
map:array [0..201] of longint;
mat:array [0..201] of equation;
con:array [0..201] of double;
o:double;
procedure swap (var a,b:double);inline;
var
i:double;
begin
i:=a;
a:=b;
b:=i;
end;
procedure dfs (now:longint;var o:st;var root:ty1;var point,next:ty2);
var
i:longint;
begin
o[now]:=true;
i:=root[now];
while i<>0 do
begin
if not o[point[i]] then
dfs(point[i],o,root,point,next);
i:=next[i];
end;
end;
procedure calc (who:longint);
var
tot,i,j,k,count:longint;
begin
tot:=0;
i:=beg[who];
while i<>0 do
begin
inc(tot);
map[tot]:=i;
num[i]:=tot;
k:=roo[i];
while k<>0 do
begin
dec(dd[form[poi[k]]]);
if (not fin[form[poi[k]]])and(dd[form[poi[k]]]=0) then
begin
fin[form[poi[k]]]:=true;
inc(all);
stack[all]:=form[poi[k]];
end;
k:=nex[k];
end;
i:=pre[i];
end;
for i:=1 to tot do
begin
fillchar(mat[i],sizeof(mat[i]),0);
mat[i,i]:=1;
if map[i]=t then
begin
con[i]:=0;
continue;
end
else
con[i]:=1;
count:=0;
k:=root[map[i]];
while k<>0 do
begin
inc(count);
k:=next[k];
end;
k:=root[map[i]];
while k<>0 do
begin
if form[point[k]]=who then
mat[i,num[point[k]]]:=mat[i,num[point[k]]]-1/count
else
con[i]:=con[i]+ans[point[k]]/count;
k:=next[k];
end;
end;
for i:=1 to tot-1 do
begin
if abs(mat[i,i])<eps then
for j:=i+1 to tot do
if abs(mat[j,i])>eps then
begin
mat[0]:=mat[i];
mat[i]:=mat[j];
mat[j]:=mat[0];
swap(con[i],con[j]);
end;
for j:=i+1 to tot do
if abs(mat[j,i])>eps then
begin
o:=mat[j,i]/mat[i,i];
con[j]:=con[j]-con[i]*o;
for k:=i to tot do
mat[j,k]:=mat[j,k]-mat[i,k]*o;
end;
end;
for i:=tot downto 1 do
begin
o:=con[i];
for j:=i+1 to tot do
o:=o-mat[i,j]*ans[map[j]];
ans[map[i]]:=o/mat[i,i];
end;
end;
procedure tarjan (now:longint);
var
i:longint;
begin
inc(all);
stack[all]:=now;
yes[now]:=true;
dfn[now]:=all;
low[now]:=all;
i:=root[now];
while (now<>t)and(i<>0) do
begin
if not yes[point[i]] then
begin
tarjan(point[i]);
if low[now]>low[point[i]] then
low[now]:=low[point[i]];
end
else
if form[point[i]]=0 then
if low[now]>dfn[point[i]] then
low[now]:=dfn[point[i]];
i:=next[i];
end;
if dfn[now]=low[now] then
begin
inc(tot);
repeat
i:=stack[all];
dec(all);
form[i]:=tot;
pre[i]:=beg[tot];
beg[tot]:=i;
until i=now;
end;
end;
begin
read(n,m,s,t);
if s=t then
begin
writeln(0);
exit;
end;
for i:=1 to m do
begin
read(u,v);
point[i]:=v;
next[i]:=root[u];
root[u]:=i;
poi[i]:=u;
nex[i]:=roo[v];
roo[v]:=i;
end;
dfs(s,o1,root,point,next);
dfs(t,o2,roo,poi,nex);
if not o2[s] then
begin
writeln('INF');
exit;
end;
for i:=1 to n do
if o1[i] and (not o2[i]) then
begin
writeln('INF');
exit;
end;
for i:=1 to n do
if o1[i] and o2[i] then
if not yes[i] then
begin
all:=0;
tarjan(i);
end;
for i:=1 to n do
begin
k:=root[i];
while k<>0 do
begin
if form[point[k]]<>form[i] then
inc(dd[form[i]]);
k:=next[k];
end;
end;
all:=1;
stack[1]:=form[t];
fin[form[t]]:=true;
i:=1;
while i<=all do
begin
calc(stack[i]);
inc(i);
end;
writeln(ans[s]:0:3);
end.