CSP/NOIP新赛制内部挑战赛1 B. 逆转时间
考虑部分分数
sub 2
a都是0,也就是说不存在回溯的情况,所以就是普通的期望dp
用f[i]表示i-n的期望距离 f[u]=sum{f[v]}/size
期望得分:30pts
代码
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+5; int cnt,n,m,k,head[maxn]; struct edge { int to,nxt,v; }e[maxn<<1]; double f[maxn]; void add(int x,int y,int z) { e[++cnt].to=y; e[cnt].nxt=head[x]; e[cnt].v=z; head[x]=cnt; } int in[maxn],out[maxn]; queue <int> q; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d%d%d",&n,&m,&k); int x,y,z; for(int i=1;i<=n;i++) scanf("%d",&x); for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); in[x]++; out[x]++; add(y,x,z); } q.push(n); out[n]=1; while(!q.empty()) { int u=q.front(); q.pop(); f[u]/=out[u]; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; f[to]+=f[u]+e[i].v; in[to]--; if(!in[to]) q.push(to); } } printf("%.7lf",f[1]); return 0; }
sub 3
a[1]=1 也就是一直都可以回溯,就已经和正解做法差不多了,就不单独写实现了
正解
先跑一次拓扑序,然后找到路径
之后在对于每个点,去计算dp值,dp[u][0/1]表示这个点是否能回溯时的期望距离
还因为有的double开成了int而WA了两发
代码
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+5; const double inf=1e17; int cnt,n,m,k,head[maxn],a[maxn]; struct edge { int to,nxt,v; }e[maxn<<1]; double dp[maxn][2]; void add(int x,int y,int z) { e[++cnt].to=y; e[cnt].nxt=head[x]; e[cnt].v=z; head[x]=cnt; } int in[maxn],out[maxn],path[maxn],tot; queue <int> q; void toposort() { for(int i=1;i<=n;i++) if(!in[i]) q.push(i); while(!q.empty()) { int u=q.front(); q.pop(); path[++tot]=u; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; in[to]--; if(!in[to]) q.push(to); } } } double ss[maxn]; void calc(int x,int flag) { int siz=0,top=0; double res=0; for(int i=head[x];i;i=e[i].nxt) { int to=e[i].to; int fl=flag|a[to]; if(fl) ss[++top]=dp[to][fl]; res+=dp[to][fl]+e[i].v; siz++; } if(!siz) return; sort(ss+1,ss+top+1); reverse(ss+1,ss+top+1); double ans=res/siz; for(int i=1;i<=top;i++) { res-=ss[i]; if(siz<=i) break; ans=min(ans,(double)1.0*res/(siz-i)+(double)1.0*i*k/(siz-i)); } dp[x][flag]=min(ans,dp[x][flag]); } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d%d%d",&n,&m,&k); int x,y,z; for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); in[y]++; add(x,y,z); } toposort(); for(int i=1;i<n;i++) dp[i][0]=inf,dp[i][1]=inf; for(int i=n;i>=1;i--) { int u=path[i]; calc(u,0); calc(u,1); } printf("%0.7lf",dp[1][a[1]]); return 0; }
这是一道期望(树形的)dp,这个内容还需要多加练习啊!