bzoj1415 聪聪与可可 概率dp
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1415
题目大意是:给一张无权无向图,一个人去追另一个人,保证被追的人初始点编号小于追的人初始点编号,被追的人随机选择走一条边或选择不走,追的人走能接近被追的人且终点编号最小的一条边,单回合可走两步,求期望步数。
首先,读入图后,我们需要预处理出每一回合,严格地讲是每一步追的人选择的边。如果说这个点可以在一步范围内追到就取追到的这个点,如果两点重合(这个在接下来会有用)就设为该点,否则,接近它的这个点就必须与扩展到它的这个点步数相同。显然这个要选择bfs。
bfs完成后,我们设数组f[i][j]为追的人在i,被追的人在j,期望追到的步数。对整张图记忆化搜索,如果已经到一块返回零,一步(之前的定义,第二步留在原地)或两步追到返回1,追不到则对被追的人每种选择进行递归搜索。
实际操作时还要注意:追的人选择能接近被追的人且终点编号最小的边,所以要用vector存图并对终点字典序排序。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 const int maxn=985,maxm=985; 8 vector<int>G[maxn]; 9 int du[maxn]; 10 double f[maxn][maxn]; 11 int n,e,c,m; 12 #include<queue> 13 int near[maxn][maxn]; 14 void Spfa(int x) 15 { 16 bool vis[maxn]={0}; 17 queue<int>q; 18 near[x][x]=x; 19 q.push(x);vis[x]=1; 20 while(!q.empty()) 21 { 22 int t=q.front();q.pop(); 23 for(int i=0;i<G[t].size();i++) 24 { 25 int v=G[t][i]; 26 if(vis[v])continue; 27 if(t==x)near[x][v]=v; 28 else near[x][v]=near[x][t]; 29 vis[v]=1; 30 q.push(v); 31 } 32 } 33 } 34 const double eps=1e-6; 35 double dp(int from,int to) 36 { 37 if(f[from][to]>eps)return f[from][to]; 38 if(from==to)return 0; 39 int go=near[near[from][to]][to]; 40 if(go==to)return f[from][to]=1; 41 double ans=dp(go,to); 42 for(int i=0;i<G[to].size();i++) 43 { 44 int v=G[to][i]; 45 ans+=dp(go,v); 46 } 47 ans/=(double)(du[to]+1); 48 ans++; 49 return f[from][to]=ans; 50 } 51 int haha() 52 { 53 //freopen("cchkk.in","r",stdin); 54 //freopen("cchkk.out","w",stdout); 55 scanf("%d%d",&n,&e);scanf("%d%d",&c,&m); 56 for(int i=1;i<=e;i++) 57 { 58 int x,y;scanf("%d%d",&x,&y); 59 G[x].push_back(y);G[y].push_back(x); 60 du[x]++;du[y]++; 61 } 62 for(int i=1;i<=n;i++)sort(G[i].begin(),G[i].end()); 63 for(int i=1;i<=n;i++)Spfa(i); 64 printf("%0.3lf",dp(c,m)); 65 } 66 int sb=haha(); 67 int main(){;}
只要是活着的东西,就算是神我也杀给你看。