ZJUT 1317 掷飞盘

题目大意:

m个人位于正m边形的顶点上,彼此抛掷飞盘。他们共有两个飞盘,且开始时这两个飞盘位于相距为n的两个人的手中(相邻两个人
相距为1,依此类推)。在每次抛掷时两个飞盘被同时抛出,飞盘都以1/2的概率被抛到掷飞盘的人左边相邻的人,1/2的概率被抛到
右边相邻的人。此过程一直进行,直到两个飞盘被掷到同一个人手中,求此抛掷飞盘的游戏平均情况下(期望)会在抛掷几次后结束。

Input:
每行有两个整数m (2<m<=100),n (0 < n < m)。
Output:
对每组数据m,n,输出平均所需步数(四舍五入,保留两位小数),
如果有限步内不可能结束就输出INF。

Sample Input:
3 1
4 1
Sample Output:
4.00
INF

题目思路:

每一次掷飞盘,有4种方案,两个都顺时针,两个都逆时针,一顺一逆。

对于这4种方案,造成飞盘间隔的变化是有规律的  我们令E[i]表示间隔为i时到目标状态的所需步数

那么E[i]=E[i]/2+E[i-2]/4+E[i+2]/4+1。其中E[0]是目标状态为 0

E[n]为所求。

可以发现间隔的范围是 0-m/2,如果大于m/2可以转换一下。

先搜索一遍,标记可以到达的状态,并编号,然后对于这些状态建立方程

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

#define eps 1e-9
const int MAXN=200;
double a[MAXN][MAXN],x[MAXN];//方程的左边的矩阵和等式右边的值,求解之后x存的就是结果
int equ,var;//方程数和未知数个数

int Gauss()
{
    int i,j,k,col,max_r;
    for(k=0,col=0;k<equ&&col<var;k++,col++)
    {
        max_r=k;
        for(i=k+1;i<equ;i++)
          if(fabs(a[i][col])>fabs(a[max_r][col]))
            max_r=i;
        if(fabs(a[max_r][col])<eps)return 0;
        if(k!=max_r)
        {
            for(j=col;j<var;j++)
              swap(a[k][j],a[max_r][j]);
            swap(x[k],x[max_r]);
        }
        x[k]/=a[k][col];
        for(j=col+1;j<var;j++)a[k][j]/=a[k][col];
        a[k][col]=1;
        for(i=0;i<equ;i++)
          if(i!=k)
          {
              x[i]-=x[k]*a[i][k];
              for(j=col+1;j<var;j++)a[i][j]-=a[k][j]*a[i][col];
              a[i][col]=0;
          }
    }
    return 1;
}

int n,m;
int num[MAXN];
int cnt;
int getnum(int x)
{
    x=(x%n+n)%n;
    if(x>n-x)x=n-x;
    return x;
}
void dfs(int x)
{
    x=getnum(x);
    num[x]=cnt++;
    int y=getnum(x+2);
    if(num[y]==-1)dfs(y);
    y=getnum(x-2);
    if(num[y]==-1)dfs(y);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(num,-1,sizeof(num));
        cnt=0;
        m=getnum(m);
        dfs(m);
        if(num[0]==-1)
        {
            printf("INF\n");
            continue;
        }
        memset(a,0,sizeof(a));
        memset(x,0,sizeof(x));
        for(int i=0;i<n;i++)
          if(num[i]!=-1)
          {
              int now=num[i];
              a[now][now]=2;
              x[now]=4;
              int t=getnum(i-2);
              a[now][num[t]]-=1;//这里一定要注意的,要减1,不能直接赋值为-1,
              t=getnum(i+2);//因为i-2和i+2是可能一样的
              a[now][num[t]]-=1;
          }
        int t=num[0];
        memset(a[t],0,sizeof(a[t]));
        a[t][t]=1;
        x[t]=0;
        equ=var=cnt;//这个不要忘记了,经常忘掉!!!
        if(Gauss())printf("%.2lf\n",x[num[m]]);
        else printf("INF\n");
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值