• BZOJ 1415


    本题是我第一道A掉的NOI题~ 啪啪啪。。

    参考了tky的论文,他的题解很详尽易懂,下面对这个经典题目的经典解法作个推导和总结。

    第一个拦路虎是如何求出鼠和猫的位置为(a,b)时猫的下一步行动。我们设p[a][b]为猫位于a,鼠位于b时猫下一步走到的节点。由于这个图没有边权,所以这个p是可以通过n次BFS预处理出来的(这个BFS的细节需要特别注意,详见代码)。

    然后我们考虑枚举所有情况来计算期望。

    先看一般情况,设f[a][b]为猫位于a,鼠位于b时,猫抓到鼠的数的期望,则猫走两之后的位置为p[p[a][b], b]。然后鼠会走到相邻接点或不动,概率相等,设之为c,所以状态会转移到f[p[a][b], c]。采用记忆化搜索,枚举c,根据定义计算期望即可。

    最后是DP的边界,a=b时返回0,p[a][b]=b或p[p[a][b], b]=b时返回1。

    写代码的时候打错了一个变量名,RE/TLE/WA了五六次(本题总AC率>50%)。。羞耻MAX...

    // BZOJ 1415
    
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
     const int N=1000+5, M=N*2;
    
     #define rep(i,a,b) for (int i=a; i<=b; i++)
     #define read(x) scanf("%d", &x)
     #define fill(a,x) memset(a, x, sizeof(a))
    
     double f[N][N];
     int p[N][N], n, m, a, b, u, v;
    
     struct Graph {
     	int s, to[M], pre[M], last[N], deg[N]; // deg为每个点的度
     	void init() { s=-1; fill(last, -1); fill(deg, 0); }
     	void ine(int a, int b, int d) {
     		s++;
     		to[s]=b, pre[s]=last[a];
     		last[a]=s;
     	}
     	void ine2(int a, int b, int d) {
     		ine(a, b, d);
     		ine(b, a, d);
     		deg[a]++; deg[b]++;
     	}
     } G;
     #define reg(i,s,u) for (int i=s.last[u]; i!=-1; i=s.pre[i])
    
     double DP(int x, int y) {
     	int arv=p[p[x][y]][y];  // 命名来源为arrive,表示走两次以后到达的结点。用临时变量储存,使之后的代码更简洁
     	if (f[x][y]>0) return f[x][y];
     	if (x==y) return 0;
     	if (p[x][y]==y || arv==y) return f[x][y]=1;
     	double sum=DP(arv, y); // 待在原地不动
        reg(i,G,y) sum+=DP(arv, G.to[i]);
        return f[x][y]=sum/(G.deg[y]+1)+1;
     }
    
     int Q[N*4], d[N]; // 队列开到2*N可能不够,要多开几倍
     void BFS(int s) {
     	int head=1, tail=1;
     	fill(d, -1); // 全部置为-1,方便BFS过程中判断
     	Q[1]=s; d[s]=0;
     	while (head<=tail) {
     		int x=Q[head++], tmp=p[s][x];
     		reg(i,G,x) {
     			int y=G.to[i];
     			if (d[y]==-1 || (d[x]+1==d[y] && tmp<p[s][y])) { // 注意判断条件:该节点没有被访问过或者路程相等但当前标号更小
     				d[y]=d[x]+1;
     				if (!tmp) p[s][y]=y; else p[s][y]=tmp;
     				Q[++tail]=y;
     			}
     		}
     	}
     }
    
    int main()
    {
    	G.init();
    	read(n); read(m); read(a); read(b);
    	rep(i,1,m) read(u), read(v), G.ine2(u,v,1);
    	rep(i,1,n) BFS(i);
    
        fill(f, 0);
    	printf("%.3lf
    ", DP(a, b));
    	
    	return 0;
    }
    



  • 相关阅读:
    面试题:链表倒数第k个节点
    面试题:重建二叉树
    面试题:从尾到头打印链表
    面试题:第一个出现的字符位置
    面试题:调整数组顺序
    面试题:有限制条件的求和
    面试题:Fibonacci数列
    面试题:旋转数组的最小数字
    面试题:替换空格
    EndNote8破解版下载安装
  • 原文地址:https://www.cnblogs.com/yearwhk/p/5119867.html
Copyright © 2020-2023  润新知