2019 ICPC 南京网络赛 D.Robots
题目给出n个点和m条有向边,机器人从1走到n,询问消耗的能量的期望。
如果只是求1到n的期望天数,就是很简单的套路题了,设dp[i]表示从i走到n的期望天数,容易得到dp[i]=p*dp[i]+(1-p)*dp[j]+1,其中p表示原地不动的概率。
比赛的时候求出天数之后就不会做了,没有细想,其实再叠加一曾,再做一次就可以了,设能量消耗是cost[i],一样有一个方程cost[i]=p *cost[i]+(1-p)*cost[j]+dp[i];
同样的方法做两次,服了。
写的时候利用拓扑,每次处理出度为0的点,一直处理到点1.
下面是AC代码:
#include <bits/stdc++.h>
using namespace std;
vector<int> a[100005];
vector<int> b[100005];
int vis1[100005];
int vis2[100005];
double dp[100005];
double cost[100005];
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
int j=1;while(j<=n)
{
a[j].clear();
b[j].clear();
vis1[j]=0;
vis2[j]=0;
dp[j]=0;
cost[j]=0;
j++;
}
int i=1;while(i<=m)
{
int x,y;
scanf("%d%d",&x,&y);
a[y].push_back(x);
b[x].push_back(y);
vis1[x]++;
vis2[x]++;
i++;
}
vector<int>tt;
tt.push_back(n);
while(tt.size())
{
int temp=tt[0];
tt.erase(tt.begin());
int t1=b[temp].size();
if(t1==0) dp[temp]=0;
else
{
double sum=0;
int k=0;while(k<t1)
{
sum=sum+dp[b[temp][k]];
k++;
}
dp[temp]=1.0*(sum+t1+1)/t1;
}
int k=0;while(k<a[temp].size())
{
vis1[a[temp][k]]--;
if(vis1[a[temp][k]]==0)
{
tt.push_back(a[temp][k]);
}
k++;
}
}
tt.push_back(n);
while(tt.size())
{
int temp=tt[0];
tt.erase(tt.begin());
int t1=b[temp].size();
if(t1==0) cost[temp]=0;
else
{
double sum=0;
int k=0;while(k<t1)
{
sum=sum+cost[b[temp][k]];
k++;
}
cost[temp]=1.0*(sum+(t1+1)*dp[temp])/t1;
}
int k=0;while(k<a[temp].size())
{
vis2[a[temp][k]]--;
if(vis2[a[temp][k]]==0)
{
tt.push_back(a[temp][k]);
}
k++;
}
}
printf("%.2lf\n",cost[1]);
}
return 0;
}