2019南京预选赛 The Preliminary Contest for ICPC Asia Nanjing 2019 D. Robots

题目链接: https://nanti.jisuanke.com/t/41301

题意:

给你一个 n n n 个点的有向无环图,保证只有点 1 1 1 的入度为 0 0 0 ,点 n n n 的出度为 0 0 0 。现在有人从点 1 1 1 出发,它能等概率的走到它能走到的下一个点或者停留一天,即有 k k k 个出度时,停下和走任意一条路的概率都为 1 / ( k + 1 ) 1/(k+1) 1/(k+1) ,每一天的消耗为已经经过的天数(包括当天),问你走到点 n n n 的期望消耗为多少。

做法:

d p dp dp 的做法应该是没问题的,但是这道题比较特殊,是不能正推出结果的,需要倒推(为什么不能正推…我也不是很清楚…)

我们维护两个 d p dp dp c o s t [ i ] cost[i] cost[i] s t e p [ i ] step[i] step[i] ,分别表示从点 i i i 出发到点 n n n 期望的消耗和期望的天数,初始情况为 c o s t [ i ] = 0 , s t e p [ i ] = 0 cost[i]=0,step[i]=0 cost[i]=0,step[i]=0 ,假设有一条边 u − > v x u->v_{x} u>vx ,已知 u u u 的出度 d [ u ] d[u] d[u] , 那么 s t e p [ u ] = ( ∑ ( s t e p [ v x ] + 1 ) + s t e p [ u ] + 1 ) / ( d [ u ] + 1 ) step[u]=(\sum(step[v_{x}]+1)+step[u]+1)/(d[u]+1) step[u]=((step[vx]+1)+step[u]+1)/(d[u]+1) ,前者是所有的 v v v 传给 u u u 的,后者是 u u u 自己停留的期望,我们将分母乘一下约一下会得到

s t e p [ u ] = ( ∑ ( s t e p [ v x ] + 1 ) + 1 ) / d [ u ] step[u]=(\sum(step[v_{x}]+1)+1)/d[u] step[u]=((step[vx]+1)+1)/d[u]

同理对于消耗,我们可以得到公式 c o s t [ u ] = ( ∑ ( c o s t [ v x ] + s t e p [ v x ] + 1 ) + c o s t [ u ] + s t e p [ u ] + 1 ) / ( d [ u ] + 1 ) cost[u]=(\sum(cost[v_{x}]+step[v_{x}]+1)+cost[u]+step[u]+1)/(d[u]+1) cost[u]=((cost[vx]+step[vx]+1)+cost[u]+step[u]+1)/(d[u]+1) ,化简可得

c o s t [ u ] = ( ∑ ( c o s t [ v x ] + s t e p [ v x ] + 1 ) + s t e p [ u ] + 1 ) / d [ u ] cost[u]=(\sum(cost[v_{x}]+step[v_{x}]+1)+step[u]+1)/d[u] cost[u]=((cost[vx]+step[vx]+1)+step[u]+1)/d[u]

然后反向建边拓扑, c o s t [ 1 ] cost[1] cost[1] 就是我们要的答案。

代码

#include 
#define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
#define lson rt<<1
#define rson rt<<1|1
#define mid (l+r)/2
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=100005;
const int maxm=400005;
const int inf=0x3f3f3f3f;
int in[maxn],head[maxn],cnt;
int nex[maxm],to[maxm],n,m,de[maxn];
double st[maxn],co[maxn];
queue<int> Q;
void add(int u,int v){
    to[cnt]=v,nex[cnt]=head[u];
    head[u]=cnt++;
}
void init(){
    rep(i,1,n) head[i]=-1,co[i]=st[i]=0.0,in[i]=de[i]=0;
    cnt=0;
}
int main(){
    int T; scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        init();
        rep(i,1,m){
            int x,y; scanf("%d%d",&x,&y);
            add(y,x); in[x]++; de[x]++;
        }
        co[n]=0.0;
        st[n]=0.0;
        Q.push(n);
        while(!Q.empty()){
            int u=Q.front(); Q.pop();
            if(u!=n) {
                st[u]+=(double)1.0/de[u];
                co[u]+=(double)(st[u]+1.0)/de[u];
            }
            for(int i=head[u];~i;i=nex[i]){
                int v=to[i];
                st[v]+=(double)(st[u]+1.0)/(de[v]*1.0);
                co[v]+=(double)(co[u]+st[u]+1.0)/(de[v]*1.0);
                if(--in[v]==0) Q.push(v);
            }
        }
        printf("%.2f\n",co[1]);
    }
    return 0;
}

你可能感兴趣的:(dp,思维)