当前位置:编程学习 > C/C++ >>

ZJUT 1317 掷飞盘 (高斯解期望问题)

题目:有m个人,围成一个圈,有两个飞盘,1/2的概率往左往右掷,最初两个飞盘相隔n,问两个飞盘到一个人手中的期望次数为多少。
http://acm.zjut.edu.cn/ShowProblem.aspx?ShowID=1317 
每一次掷飞盘,有4种方案,两个都顺时针,两个都逆时针,一顺一逆。
对于这4种方案,造成飞盘间隔的变化是有规律的  我们令E[i]表示间隔为i时到目标状态的所需步数
那么E[i]=(2*E[i]+E[i-2]+E[i+2])/4。其中E[0]是目标状态为 0
E[n]为所求。
可以发现间隔的范围是 0-m/2,如果大于m/2可以转换一下。
一开始可能处理得非常麻烦,分了很多情况以及奇偶
不过可以直接转换,如果出现负的则转正,如果出现大于上界,则取另外一边的。
开始的WA是因为没有考虑到有一些状态不可达,又忽视了这个重要的地方。
先搜索一遍,标记可以到达的状态,并编号,然后对于这些状态建立方程
[cpp] 
#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<queue> 
#include<vector> 
#include<cmath> 
#define LL long long 
#define MOD 1000000007 
#define eps 1e-6 
#define zero(a)  fabs(a)<eps 
using namespace std; 
int n,m,num[105],cnt,tot; 
double a[105][105]; 
void debug(int n){ 
    for(int i=0;i<n;i++){ 
        for(int j=0;j<=n;j++) 
           printf("%.2f ",a[i][j]); 
        printf("\n"); 
    } 

int get(int x){ 
    if(x<0) x=-x; 
    if(x>tot) x=m-x; 
    return x; 
} www.zzzyk.com
void dfs(int x){ 
    num[x]=cnt++; 
    int t=get(x-2); 
    if(num[t]==-1) dfs(t); 
    t=get(x+2); 
    if(num[t]==-1) dfs(t); 

bool gauss(int n){ 
    int i,j; 
    for(i=0,j=0;i<n&&j<n;j++){ 
        int k; 
        for(k=i;k<n;k++) 
            if(!zero(a[k][j])) 
                break; 
        if(k<n){ 
            if(i!=k) 
            for(int r=j;r<=n;r++) swap(a[i][r],a[k][r]); 
            double tt=1/a[i][j]; 
            for(int r=j;r<=n;r++) 
                a[i][r]*=tt; 
            for(int r=0;r<n;r++) 
                if(r!=i){ 
                    for(int t=n;t>=j;t--) 
                        a[r][t]-=a[r][j]*a[i][t]; 
                } 
            i++; 
        } 
    } 
    for(int r=i;r<n;r++) 
        if(!zero(a[r][n])) 
            return false; 
    return true; 

int main(){ 
    while(scanf("%d%d",&m,&n)!=EOF){ 
        if(n>m/2) n=m-n; 
        if(n==0){printf("0.00\n");continue;} 
        if(m%2==0&&n==1) {printf("INF\n");continue;} 
        tot=m/2; 
        memset(num,-1,sizeof(num)); 
        cnt=0; 
        dfs(n); 
        if(num[0]==-1) {printf("INF\n");continue;} 
        memset(a,0,sizeof(a)); 
        a[num[0]][num[0]]=1; 
        for(int i=1;i<=tot;i++){ 
            if(num[i]!=-1){ 
                int j=num[i]; 
                a[j][j]=-2;a[j][cnt]=-4; 
                int t=get(i-2); 
                a[j][num[t]]++; 
                t=get(i+2); 
                a[j][num[t]]++; 
            } 
        } 
       // debug(cnt); 
        if(gauss(cnt)){ 
            for(int i=0;i<cnt;i++) 
                if(zero(a[i][num[n]]-1)) 
                     printf("%.2f\n",a[i][cnt]); 
        } 
        else 
            puts("INF"); 
    } 
    return 0; 


 

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,