传送门
题解:
首先考虑没有自环的情况。
先考虑没有边权重排的情况,这个时候显然是贪心选择最小后继。
然后考虑边权存在重排怎么做。设度数为 d d d,显然要考虑的是 d 2 d^2 d2个后继组合(边 × \times ×点)被选择的情况。
直接排个序,用堆维护匹配的同时算一下条件概率转移即可,精度爆炸的时候要自行退出。
如果有自环,直接二分或者迭代即可。
复杂度就没有哪个地方是满的。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs double eps=1e-8;
cs int N=1e3+7;
int n,m,S,T;
int el[N],nxt[N],to[N],ec;double w[N];
inline void adde(int u,int v,double vl){
nxt[++ec]=el[u],el[u]=ec,to[ec]=v,w[ec]=vl;
}
struct node{
int v;double w;
friend bool operator<(cs node &a,cs node &b){
return a.w>b.w;
}
};
int ct,ps[N];
double E[N],a[N],b[N];
bool toT[N],vis[N];
inline double calc(){
std::priority_queue<node> q;
for(int re i=1;i<=ct;++i)q.push((node){i,a[i]+b[1]}),ps[i]=ct;
double p=1,res=0;
while(!q.empty()&&p>0){
node t=q.top();q.pop();
int v=t.v;double w=t.w;
double tmp=p*(ps[v]-v)/(ps[v]-v+1.);
--ps[v];res+=w*(p-tmp);p=tmp;
if(ps[v]>=1)q.push((node){v,a[v]+b[ct-ps[v]+1]});
}
return res;
}
void dfs(int u){
vis[u]=true;bool sel=false;
if(u==T){toT[u]=true;return ;}
for(int re e=el[u];e;e=nxt[e]){
if(!vis[to[e]])dfs(to[e]);
toT[u]|=toT[to[e]];
}if(!toT[u]){E[u]=1e10;return ;}
ct=0;for(int re e=el[u];e;e=nxt[e])a[++ct]=w[e],sel|=to[e]==u;
std::sort(a+1,a+ct+1);
if(!sel){
ct=0;for(int re e=el[u];e;e=nxt[e])b[++ct]=E[to[e]];
std::sort(b+1,b+ct+1);E[u]=calc();return ;
}
double l=0,r=1e6;
while(l+eps<r){
E[u]=(l+r)*0.5;
ct=0;for(int re e=el[u];e;e=nxt[e])b[++ct]=E[to[e]];
std::sort(b+1,b+ct+1);calc()>E[u]?l=E[u]:r=E[u];
}E[u]=l;
}
signed main(){
#ifdef zxyoi
freopen("shuffle.in","r",stdin);
#endif
scanf("%d%d%d%d",&n,&m,&S,&T);
for(int re i=1;i<=m;++i){
int u,v;double vl;
scanf("%d%d%lf",&u,&v,&vl);
adde(u,v,vl);
}dfs(S);
if(!toT[S])puts("-1");
else printf("%.7lf",E[S]);
return 0;
}