HDU 5001 Walk

54 篇文章 0 订阅

这道题的精度卡的人难受死了。

按照老师思路做的,矩阵的值表示i走到j的概率,求不经过某点的概率。

起始位置每个点的概率是1/N,然后将那个点外出的边都去掉,矩阵N次后,即可得到走到该点的概率,1-P即可。

注意:这道题有精度问题,可能会过小出现负数,1e-6

在构图的时候为了避免每次N循环,可以将每条边的连接顺序放入容器vector中,.size()就都有了。

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <bitset>
#include <iostream>
#include <algorithm>  
#define inf 0x3fffffff
#define mid ((l+r)>>1)
const int maxn=100000+100;
typedef unsigned __int64 ull;
using namespace std;
int N,M,D;
double A[55][55],B[55][55],C[55][55];
double X[55][55];
int G[55][55];
double tt[2][55];
void matrix(double (*a)[55],double (*b)[55],double (*c)[55])
{
	int i,j,k;
	for(i=0;i<N;i++)
		for(j=0;j<N;j++)
		{
			c[i][j]=0;
			for(k=0;k<N;k++)
				c[i][j]+=a[i][k]*b[k][j];
		}
}
void qmaxtrix(int d)
{
	int i,j,k;
	memset(C,0,sizeof(C));
	for(i=0;i<N;i++)
		C[i][i]=1;
	while(d)
	{
		if(d&1)
			matrix(C,A,B),memcpy(C,B,sizeof(B));
		matrix(A,A,B),memcpy(A,B,sizeof(B));
		d>>=1;
	}


}
int main()
{
    int T;
    int n,m,cas=1;
	int i,j,k;
	double ans;
    scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d",&N,&M,&D);
		memset(G,0,sizeof(G));
		memset(X,0,sizeof(A));
		for(i=0;i<M;i++)
			scanf("%d%d",&n,&m),G[n-1][m-1]=G[m-1][n-1]=1;
		double tmp=0;
		for(i=0;i<N;i++)
		{
			tmp=0;
			for(j=0;j<N;j++)
				if(G[i][j]) 
					tmp++;
			if(tmp<1e-8) continue;
			tmp=1/tmp;
			for(j=0;j<N;j++)
				if(G[i][j]) X[i][j]=tmp;
		}
		for(i=0;i<N;i++)
		{
			memcpy(A,X,sizeof(A));
			for(j=0;j<N;j++)
				A[i][j]=0;
			A[i][i]=1;
			qmaxtrix(D);
			ans=1;
			for(j=0;j<N;j++)
					ans-=(1.0/N)*C[j][i];
			if(ans<0) ans+=1e-6;
			printf("%.10lf\n",ans);
		}


	}
    return 0;
}

老师版本,构图不一样。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<memory.h>
#include<vector>
#include<math.h>
using namespace std;

#define MAX 55
vector< vector<int> > edge;
int n, m, d;
double p[MAX][MAX];
#define E 1e-6
double CalRes(int k)
{
    int st;
    double val = 1.0;
    for(st = 0; st < n; st++)
    {
        val -= 1.0 / n * p[st][k];
    }
    if(val < 0)
    {
        val += E;
    }
    return val;
}
double A[MAX][MAX];
double B[MAX][MAX];
double C[MAX][MAX];
void Mul()
{
    int i, j, k;
    for(i = 0; i < n; i++)
    {
        for(j = 0; j < n; j++)
        {
            C[i][j] = 0.0;
            for(k = 0; k < n; k++)
            {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}
void CalPowA()
{
    double res[MAX][MAX];
    double D[MAX][MAX];
    int i;
    memset(res, 0, sizeof(res));
    for(i = 0; i < n; i++)
    {
        res[i][i] = 1.0;
    }
    memcpy(D, p, sizeof(p));
    int step = d;
    while(step)
    {
        if(step % 2)
        {
            memcpy(A, res, sizeof(res));
            memcpy(B, D, sizeof(D));
            Mul();
            memcpy(res, C, sizeof(C));
        }
        memcpy(A, D, sizeof(D));
        memcpy(B, D, sizeof(D));
        Mul();
        memcpy(D, C, sizeof(C));
        step /= 2;
    }
    memcpy(p, res, sizeof(res));
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "rt", stdin);
    freopen("out.txt", "wt", stdout);
#endif
    int T;
    cin>>T;
    int i, j, a, b;
    for(; T; T--)
    {
        cin>>n>>m>>d;
        edge.clear();
        edge.resize(n);
        for(i = 0; i < m; i++)
        {
            cin>>a>>b;
            a--;
            b--;
            edge[a].push_back(b);
            edge[b].push_back(a);
        }
        int k;
        for(k = 0; k < n; k++)
        {
            memset(p, 0, sizeof(p));
            for(i = 0; i < n; i++)
            {
                for(j = 0; j < edge[i].size(); j++)
                {
                    p[i][edge[i][j]] = 1.0 / edge[i].size();
                }
            }
            for(i = 0; i < n; i++)
            {
                p[k][i] = 0;
            }
            p[k][k] = 1.0;
            CalPowA();
            printf("%.10lf\n", CalRes(k));
        }
    }
    return 0;
}

或者动态规划,每步是一个状态,这样dp[i][j] 表示走了i步走到j的概率。在计算的时候每走到这次计算的I的时候就停下.

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std; 
#define INF 1000000000
//typedef __int64 LL; 
#define N 10005
int t, n, d, m; 
double dp[N][52]; 
vector<int > save[55]; 
int main() 
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin); 
#endif // ONLINE_JUDGE
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d%d", &n, &m, &d); 
        for(int i = 0; i <= n; i++) save[i].clear(); 
        int u, v; 
        for(int i = 1; i <= m; i++) {
            scanf("%d%d", &u, &v); 
            save[u].push_back(v); 
            save[v].push_back(u); 
        }
        for(int i = 1; i <= n; i++) {
            memset(dp, 0, sizeof(dp)); 
            for(int j = 1; j <= n; j++) dp[0][j] = 1.0 / n; 

            for(int id = 1; id <= d; id ++) {
                for(int j = 1; j <= n; j++) {
                    if(j == i) continue; 
                    int ddd = save[j].size(); 
                    for(int kk = 0; kk < ddd; kk++) {
                        int k = save[j][kk]; 
                        dp[id][k] += 1.0 * dp[id - 1][j] / ddd ; 
                    }
                }
            }
            double ans = 0; 
            for(int j = 1; j <= n; j++) {
                if(j == i) continue; 
                ans += dp[d][j]; 
            }
            printf("%lf\n", ans); 
        }
    }
    return 0; 
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值