HDU - 6229:Wandering Robots(思维题)


题目大意:

有一个n*n的区域,左上角坐标为(0,0),在左上角有一个机器人,他每次留在原地和前往其他可前往的格子的概率相等,最后若干时间之后,求机器人最后在(x,y)(x+y>=n-1)的点的概率是多少。


题解:

训练赛的时候碰到的题目, 当时完全不知道怎么做。赛后查题解的时候震惊了,竟然还有这种做法。大佬们比赛的时候都是怎么想到的。。。膜拜.......

 具体解法就是给每个点赋一个权值,权值的大小就代表当前点可以被几个点所到达(包括自身),理论上一个无障碍的图中,4个角落的点的权值为3,边缘除角落的权值为4,其余点权值为5,然后我们就神奇的发现,分母就是所有点的权值和,分子是所有终点的权值和。这样大体的解法就出来了。

之后因为n=10000,所以不能裸暴力,但是因为障碍最多只有1000个,所以我们可以用map把所有的障碍事先存起来。之后对于这些点枚举,用总贡献减去这些点的贡献即可。

这里有个问题就是如果障碍恰好一圈把障碍围起来,理论上这些点的权值应该都是0,我这里没有考虑,其实应该考虑这个问题的。。。


Ac代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int n,m,p,q;
map<pair<int,int>,int> ma;
int check(int x,int y)  //判断当前点的贡献
{
    if((x==0||x==n-1)&&(y==0||y==n-1))  return 3;
    if((x==0||x==n-1)&&(y!=0&&y!=n-1))  return 4;
    if((y==0||y==n-1)&&(x!=0&&x!=n-1))  return 4;
    return 5;
}
int main()
{
    int QAQ,kase=0;
    scanf("%d",&QAQ);
    while(QAQ--)
    {
        ma.clear();p=0,q=0;
        scanf("%d%d",&n,&m);
        while(m--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            ma[make_pair(x,y)]=1;
        }
        if(n==1)    //n==1 特判
        {
            if(m==1) printf("0\n");
            else printf("1");
        }
        else
        {
            q+=((3*4)+((n-2)*4*4)+(n-2)*(n-2)*5);   //分母
            p+=((3*3)+((n-2)*2*4)+((n-2)*(n-1)/2*5));   //分子
            for(auto it=ma.begin();it!=ma.end();it++)   //遍历所有障碍
            {
                int x=it->first.first;
                int y=it->first.second;
                q-=check(x,y);  //减去对分母的贡献
                if(x+y>=n-1) p-=check(x,y);     //减去对分子的贡献
                for(int i=0;i<4;i++)    //判断对周围点的贡献的影响
                {
                    int xx=x+dx[i];
                    int yy=y+dy[i];
                    if(xx>=0&&xx<n&&yy>=0&&yy<n&&ma.count(make_pair(xx,yy))==0)
                    {
                        if(xx+yy>=n-1) p--;
                        q--;
                    }
                }
            }
            int gk=__gcd(p,q);  //化简
            printf("Case #%d: %d/%d\n",++kase,p/gk,q/gk);
        }
    }
    system("pause");
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值