Walk
Time Limit: 30000/15000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 267 Accepted Submission(s): 184
Special Judge
The nation looks like a connected bidirectional graph, and I am randomly walking on it. It means when I am at node i, I will travel to an adjacent node with the same probability in the next step. I will pick up the start node randomly (each node in the graph has the same probability.), and travel for d steps, noting that I may go through some nodes multiple times.
If I miss some sights at a node, it will make me unhappy. So I wonder for each node, what is the probability that my path doesn't contain it.
For each test case, the first line contains 3 integers n, m and d, denoting the number of vertices, the number of edges and the number of steps respectively. Then m lines follows, each containing two integers a and b, denoting there is an edge between node a and node b.
T<=20, n<=50, n-1<=m<=n*(n-1)/2, 1<=d<=10000. There is no self-loops or multiple edges in the graph, and the graph is connected. The nodes are indexed from 1.
Your answer will be accepted if its absolute error doesn't exceed 1e-5.
题目大意:
给出n个点,m条双向边,d步。在每个点向与其相邻点移动的可能性相等,开始时每个点被选取作为起点的可能性相等。
问,所有的路径中不经过每个点的概率是多少。
反省&思路:
首先,在打这场网络赛的时候 , 犯了很严重的失误———没有好好审视好这道题的时限——15s是个人都能写个暴力程序过掉啊~!!!
思路的话,直接计算n次,每次只求出在每一步中其他每一个不经过当前删除点的的概率。
递推式为:
dp[k][j]表示在第j步走到k时前j步都没经过x的概率,
那么在某一步j中对于非x的每一个点k有
dp[k][j]=sigema(dp[kk][j-1] * (num[kk]/1)) 其中kk是与k 相邻的点,num[kk]表示与kk相邻的点的个数
WA的原因:
由于手写静态邻接链表不是很熟悉,导致:
(1)数组开小
(2)在遍历临街表的那个for里面,把kk和G[kk].to搞混
详细错误的话,看下面的代码有注释标出
下面是ac代码
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <memory.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxn 60
#define maxm 6000 //WA的罪魁祸首
using namespace std;
int t;
int n,m,d;
//vector<int> G[maxn];
int head[maxn],si;
struct edge{int to,next;} G[maxm];
double dp[60][10008],num[maxn]; //dp[i][j] 在第j步到达i点但是之前j步不经过now的概率
void addedge(int from,int to)
{
G[si].to=to;
G[si].next=head[from];
head[from]=si++;
}
void init(int now)
{
for(int i=0;i<n;i+=1){
for(int j=0;j<=d;j+=1){
dp[i][j]=0;
}
}
for(int i=0;i<n;i+=1){
if(i!=now)
dp[i][0]=1/(double)n;
}
}
int main()
{
cin>>t;
while(t--){
cin>>n>>m>>d;
int a,b;
memset(head,-1,sizeof head);
memset(num,0,sizeof num);
si=0;
for(int i=0;i<m;i+=1){
cin>>a>>b;
num[a-1]+=1;
num[b-1]+=1;
addedge(a-1,b-1);
addedge(b-1,a-1);
}
for(int i=0;i<n;i+=1){
init(i);
double res=0;
for(int j=1;j<=d;j+=1){
for(int k=0;k<n;k+=1){
for(int kk=head[k];k!=i&&kk!=-1;kk=G[kk].next){
if(/*kk!=i*/G[kk].to!=i)
//最根本的WA的原因是数组开小了,后来想来想去加了这个步骤,最后改了数组加了这步还是WA
//后来发现时注释里面的逗比错误,用if注释外的就必然过了
dp[k][j]+=(dp[G[kk].to][j-1]*(1/num[G[kk].to]));
else
cout<<"____"<<dp[i][j]<<endl;
}
}
}
for(int j=0;j<n;j+=1){
if(j!=i) //漏1
res+=dp[j][d];
}
printf("%.10lf\n",res);
}
}
return 0;
}