HDU5001 Walk (2014年鞍山赛区网络赛E题)

1.题目描述:点击打开链接

2.解题思路:本题利用矩阵快速幂+概率dp解决。根据题意可以画出来一个状态转移图,根据状态转移图不难得到一步转移概率矩阵,接下来的问题是:如何求解d步之内(包括d)均无法从其他点走到结点u的概率。

首先,既然无法到达结点u,那么出发的时候就不能选择该点。其次,为了使其他结点也无法到达结点u,可以将一步转移概率矩阵中跟结点u有关的概率全部置零。即表示u结点出发无法到达其他结点,其他结点也均无法到达u结点,这样就相当于把u结点从状态转移图中暂时删去了。然后根据马氏链的知识,假设一步转移概率矩阵为A,那么d步转移概率矩阵为A^d。再考虑到选择出发点也构成一个矩阵B,那么最终d步时候的概率矩阵为B=B*(A^d)。最终得到的B矩阵中的B[i][j]即为i经过d步走到j的概率。

这里有一个小技巧,为了便于计算B矩阵,可以在初始化的时候只将第0行的每个结点都置为1/n(结点i仍然置零),表示结点j被选为出发点的概率,这样,最终计算出的B矩阵也只在第0行有结果,表示其他点到达结点j的概率,最后,只需要把这些概率求和,即可得到到达除结点i之外其他结点的概率,即不到达结点i的概率。

本题的时间复杂度为O(N^4logd)。

3.代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
using namespace std;

#define me(s) memset(s,0,sizeof(s))
#define pb push_back
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;

const int N = 10000 + 10;
int n, m, d;
struct Node
{
	double v[55][55];
	void init()
	{
		memset(v, 0, sizeof(v));
	}
	Node operator*(Node r)
	{
		Node ans;
		ans.init();
		for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
		for (int k = 0; k < n; k++)
			ans.v[i][j] += v[i][k] * r.v[k][j];
		return ans;
	}
}a;

Node operator^(Node m, int d)
{
    Node ans;
    ans.init();
    for(int i=0;i<n;i++)ans.v[i][i]=1;
    while(d>0)
    {
        if(d&1)ans=ans*m;
        m=m*m;
        d>>=1;
    }
    return ans;
}

int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d%d", &n, &m, &d);
		int u, v;
		vector<int>g[N];
		for (int i = 0; i<m; i++)
		{
			scanf("%d%d", &u, &v);
			u--;v--;
			g[u].push_back(v);
			g[v].push_back(u);
		}
		a.init();
		for (int i = 0; i < n; i++)
		if (!g[i].empty())
		{
			int len = g[i].size();
			for (int j = 0; j<len; j++)
			{
				int id = g[i][j];
				a.v[i][id] = (double)1.0 / len;//求一步转移概率矩阵
			}
		}
		for(int i=0;i<n;i++)
        {
            Node tmp=a;
            for(int j=0;j<n;j++)
                tmp.v[i][j]=tmp.v[j][i]=0;//将与结点i有关的概率暂时置零
            Node ans;
            ans.init();
            for(int j=0;j<n;j++)
                ans.v[0][j]=1.0/n;
            ans.v[0][i]=0;  //不从结点i出发
            ans=ans*(tmp^d);
            double res=0;
            for(int j=0;j<n;j++)
                res+=ans.v[0][j];//求和,得到d步之内均不经过结点i的概率
            printf("%.10lf\n",res);
        }
	}
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 11:03:49

HDU5001 Walk (2014年鞍山赛区网络赛E题)的相关文章

HDU5006 Resistance (2014年鞍山赛区网络赛J题)

1.题目描述:点击打开链接 2.解题思路:本题利用缩点+高斯消元解决.本题的最大特点就是电阻非零即一,如果电阻为0,说明零点之间是等电位点,可以看做一个整体,自然可以想到先利用并查集进行缩点操作,将复杂的电路图转化为不相等的电位点构成的电路图.如果转换完毕后,发现s和t在一个集合中,说明两点之间是等电位的,等效电阻为0,否则,对转换后的图G'重新判断连通性,依然可以利用并查集解决,如果发现不连通,说明s与t之间开路,电阻为inf,否则,就可以根据tot个点的电位列写方程. 我们令有1A的电流从点

HDU 5002 Tree (2014年鞍山赛区网络赛F题)

1.题目描述:点击打开链接 2.解题思路:LCT的模板题 3.代码: #include <cstdio> #include <cstdlib> #include <algorithm> #include <iostream> #include <vector> using namespace std; const int N = 111111; const int INF = 1111111111; int n, m; class LCT { p

HDU4998 Rotate (2014年鞍山赛区网络赛B题)

1.题目描述:点击打开链接 2.解题思路:本题属于几何变换专题,一开始想着随便枚举两个点,然后都进行一下旋转变换,最后利用原始点和旋转后的点所在直线的中垂线的交点求解.然而发现精度损失很大,而且可能有特殊情况没有考虑到.学习了一下几何变换的方法. 由于旋转操作相当于对一个点构成的矩阵和一个旋转矩阵做乘法运算.最基本的旋转变换就是任意一个点围绕原点进行逆时针旋转.如果改成围绕某个定点(x0,y0)进行旋转可以分解为三步:将被旋转点平移(-x0,-y0),进行基本旋转变换,再平移(x0,y0).在矩

HDU5003 Osu! (2014年鞍山赛区网络赛G题)

1.题目描述:点击打开链接 2.解题思路:本题是一道简单的排序题,按照题意排序计算即可. 3.代码: #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<string> #include<sstream> #include<set> #include<vector> #include<stack> #include&

HDU 4998 Rotate(计算几何)2014年鞍山赛区网络赛

Rotate                                                                           Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Special Judge Problem Description Noting is more interesting than rotation! Your litt

ZOJ 3810 A Volcanic Island (2014年牡丹江赛区网络赛B题)

1.题目描写叙述:点击打开链接 2.解题思路:本题是四色定理的模板题.只是有几种情况要提前特判一下:n==1直接输出,1<n<5时候无解,n==6时候套用模板会出现同样的块.因此要特判一下.其它情况都能直接利用模板构造出来. 3.代码: #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<cassert> #include<string>

ZOJ 3814 Sawtooth Puzzle (2014年牡丹江赛区网络赛F题)

1.题目描写叙述:点击打开链接 2.解题思路:本题是一道隐式图的搜索题目.一般来说,这类题目首先要定义状态,接下来是弄清楚状态怎样转移,以及状态怎样判重,怎样推断当前状态是否和目标状态同样.至于求解最短路就是经常使用的BFS就可以. 接下来我们逐一展开讨论. 1.状态的定义:看到这道题,猛一下会想着把每一个字符分别用01表示,然后看成二进制码进行状态压缩,这个状态定义尽管能够,可是显然,状态过于精确和复杂,假设把一行给压缩成一个整数,那么一个完整的图案要用8*9.即72个数才干描写叙述.显然过于

ZOJ 3818 Pretty Poem (2014年牡丹江赛区网络赛J题)

1.题目描述:点击打开链接 2.解题思路:本题是一道模拟题,输入一个串,要求判断是否形如"ABABA"或"ABABCAB".只需要对两种情况逐一尝试即可.然而这道题有诸多细节需要考虑.这里说一下我自己的方法. 首先,如果输入的串长度<5,那么直接输出No,或者去掉所有的标点后发现长度<5,输出No.长度上没问题后,写一个专门的solve(int type)函数,来判断是否是上述情况中的一种.对于第一种,只需要枚举A的长度即可,B的长度就是(len-3*i

HDU-5001 Walk 2014年鞍山网络赛E题

依次枚举每个不能走过的点,DP递推下一步情况,求出所有其他点的概率之和即为这个点不会被走过的概率. #include <iostream> #include <cstdio> #include <queue> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <iomanip> #include