• @bzoj



    @description@

    有一天Petya和他的朋友Vasya在进行他们众多旅行中的一次旅行,他们决定去参观一座城堡博物馆。
    这座博物馆有着特别的样式。它包含由m条走廊连接的n间房间,并且满足可以从任何一间房间到任何一间别的房间。

    两个人在博物馆里逛了一会儿后两人决定分头行动,去看各自感兴趣的艺术品。他们约定在下午六点到一间房间会合。然而他们忘记了一件重要的事:他们并没有选好在哪儿碰面。
    等时间到六点,他们开始在博物馆里到处乱跑来找到对方(他们没法给对方打电话因为电话漫游费是很贵的)

    不过,尽管他们到处乱跑,但他们还没有看完足够的艺术品,因此他们每个人采取如下的行动方法:每一分钟做决定往哪里走,有Pi 的概率在这分钟内不去其他地方(即呆在房间不动),有1-Pi 的概率他会在相邻的房间中等可能的选择一间并沿着走廊过去。这里的i指的是当期所在房间的序号。在古代建造是一件花费非常大的事,因此每条走廊会连接两个不同的房间,并且任意两个房间至多被一条走廊连接。

    两个男孩同时行动。由于走廊很暗,两人不可能在走廊碰面,不过他们可以从走廊的两个方向通行。(此外,两个男孩可以同时地穿过同一条走廊却不会相遇)两个男孩按照上述方法行动直到他们碰面为止。
    更进一步地说,当两个人在某个时刻选择前往同一间房间,那么他们就会在那个房间相遇。

    两个男孩现在分别处在a,b两个房间,求两人在每间房间相遇的概率。

    Input
    第一行包含四个整数,n表示房间的个数;m表示走廊的数目;a,b (1 ≤ a, b ≤ n),表示两个男孩的初始位置。
    之后m行每行包含两个整数,表示走廊所连接的两个房间。
    之后n行每行一个至多精确到小数点后四位的实数 表示待在每间房间的概率。
    题目保证每个房间都可以由其他任何房间通过走廊走到。

    Output
    输出一行包含n个由空格分隔的数字,注意最后一个数字后也有空格,第i个数字代表两个人在第i间房间碰面的概率(输出保留6位小数)
    注意最后一个数字后面也有一个空格
    Sample Input
    2 1 1 2

    1 2

    0.5

    0.5

    Sample Output
    0.500000 0.500000

    HINT
    对于100%的数据有 n <= 20,n-1 <= m <= n(n-1)/2

    @solution@

    很经典的高斯消元解无后效性 dp 模板,不过网上的某些题解并没有说清楚。。。
    比如出现了我给某个概率 + 1 这种怎么推导都推导不出来的玄学东西。一个大于 1 的概率是几个意思啊。。。

    我们尝试用期望代替概率进行 dp。注意题目中所说的如果两个人相遇,那么两个人将终止行动。
    我们令 dp[(x, y)] 表示 “第一个人在 x,第二个人在 y” 这个事件的期望发生次数。
    这样定义状态有什么好处呢?我们发现当两个人相遇后他们就不动了,于是 ∑dp[(i, i)] = 1,即“到达终点”这一事件期望发生次数为 1。
    于是 dp[(i, i)] = P(i, i)*∑dp[(i, i)] = P(i, i),即两个人在 i 处相遇的期望发生次数 = 在 i 处相遇的概率 * 到达终点的期望发生次数 = 在 i 处相遇的概率。
    于是我们通过求解期望就顺便把概率也求出来了。

    至于 dp 的转移式,注意到一个状态其实有两个来源:一是它作为起点(即题目给定的 (a, b)),另一个是从上一个时刻的某一状态通过停留或移动得到。
    分类讨论一下即可。然后就可以列出方程高消。

    如果真的要用概率来推的话,我看到的一篇比较靠谱题解是这样推导:
    令 b 向量表示初始状态下两个人在 (x, y) 的概率(显然只有 b[(a, b)] = 1)。
    令 A 是一个转移矩阵,表示从前一时刻转移到现在这一时刻的概率转移,注意 (x, x) 是不能转移出去的。
    则:ans = (I + A + A^2 + ... )*b = (I - A)^(-1)*b,因为每一个时刻两个人都有可能相遇。
    写一个矩阵求逆即可。

    @accepted code@

    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int g[20 + 5][20 + 5], deg[20 + 5];
    double M[20*20 + 5][20*20 + 5], P[20 + 5];
    void gauss(int n, int m) {
    	int r = 0, c = 0;
    /*
    	for(int i=0;i<n;i++) {
    		for(int j=0;j<m;j++)
    			printf("%lf ", M[i][j]);
    		puts("");
    	}
    */
    	while( r < n && c < m ) {
    		int mxr = r;
    		for(int i=r;i<n;i++)
    			if( fabs(M[i][c]) > fabs(M[mxr][c]) )
    				mxr = i;
    		for(int i=c;i<m;i++)
    			swap(M[r][i], M[mxr][i]);
    		if( M[r][c] ) {
    			double k = M[r][c];
    			for(int i=c;i<m;i++)
    				M[r][i] /= k;
    			for(int i=0;i<n;i++) {
    				if( i == r || M[i][c] == 0 ) continue;
    				k = M[i][c];
    				for(int j=c;j<m;j++)
    					M[i][j] = M[i][j] - k*M[r][j];
    			}
    			r++;
    		}
    		c++;
    	}
    }
    int n, m, a, b;
    inline int id(int x, int y) {return x*n + y;}
    int main() {
    	scanf("%d%d%d%d", &n, &m, &a, &b), a--, b--;
    	for(int i=1;i<=m;i++) {
    		int x, y; scanf("%d%d", &x, &y), x--, y--;
    		g[x][y] = g[y][x] = 1, deg[x]++, deg[y]++;
    	}
    	for(int i=0;i<n;i++)
    		scanf("%lf", &P[i]);
    	for(int i=0;i<n;i++)
    		for(int j=0;j<n;j++) {
    			M[id(i, j)][id(i, j)] = -1;
    			for(int x=0;x<n;x++)
    				for(int y=0;y<n;y++) {
    					if( x == y ) continue;
    					if( i == x && j == y )
    						M[id(i, j)][id(x, y)] += P[x]*P[y];
    					if( i == x && j != y && g[j][y] )
    						M[id(i, j)][id(x, y)] += P[x]*(1 - P[y])/deg[y];
    					if( i != x && j == y && g[i][x] )
    						M[id(i, j)][id(x, y)] += (1 - P[x])/deg[x]*P[y];
    					if( i != x && j != y && g[i][x] && g[j][y] )
    						M[id(i, j)][id(x, y)] += (1 - P[x])/deg[x]*(1 - P[y])/deg[y];
    				}
    		}
    	int p = n*n;
    	M[id(a, b)][p] = -1;
    	gauss(p, p + 1);
    	for(int i=0;i<n;i++)
    		printf("%lf ", M[id(i, i)][p]);
    }
    

    @details@

    当作高斯消元复习的模板题好了。。。

  • 相关阅读:
    NOIP初赛篇——02计算机系统的基本结构
    NOIP初赛篇——01计算机常识
    C++语言基础——02数据的存取
    加密时java.security.InvalidKeyException: Illegal key size or default parameters解决办法
    log4j.properties配置文件的内容
    Windows如何关闭占用某一端口的进程
    【JAVA】别特注意,POI中getLastRowNum() 和getLastCellNum()的区别
    【JAVA】POI设置EXCEL单元格格式为文本、小数、百分比、货币、日期、科学计数法和中文大写
    【JAVA】使用Aphache poi操作EXCEL 笔记
    Flex自定义组件、皮肤,并调用
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/11136492.html
Copyright © 2020-2023  润新知