论随机数AC大法(1)

本人蒟蒻!!
所以只能靠随机数这种我自己都不知道从哪儿学来的黑科技乱做题,做题一年多后,颇有体会(WA遍各大OJ),所以特此写下此博客,纪念我OI历程,并向广大OIer们介绍一种玄学……
这里写图片描述

真的能AC吗?

我的随机数分为两种,一种是纯靠脸(一般这种死的很惨或活的很傲娇……),另一种就是以随机+卡时为主,尽可能地多得分,后者对与OI的代码实现能力要求高一点(其实也没多高……),也更加稳定。不外乎是做不出来,暴力分很少,需要放手一搏时的好方法。

NOIP、NOI评测时一般评测两次,若两次不一样则重新评测取最后一次!!

example:

来自风平浪静的明天

这里写图片描述
这里写图片描述
【题目描述】
冬眠了五年,光终于从梦中醒来。
千咲、要,大家都在。
隐约记得“昨天”的海船祭,爱花意外成为贡女,沉入海底。
海面冰封,却有丝丝暖流在冰面之下涌动。
此时,爱花沉睡在祭海女神的墓地。她的胞衣在一点点脱落,化作一簇簇暖流,夹杂着她的感情,向海面上涌去。
爱花,你在哪里?
五年之后,纺已经成为海洋学研究科的大学生。
在纺的帮助下,光得知了海面下海流的情况。
纺告诉光,暖流一旦产生,就会不断地向四周扩散,直到遇到海中的岩石。
红腹海牛,快告诉光,爱花在哪里。
纺帮你绘制了一张海流情况图,长度为N,宽度为M。
海很大,一边有沙滩,一边一望无际,但长度和宽度都不会超过300。沙滩是金黄色的,所以用Y表示。海是蓝色的,所以用B表示。暖流很暖和,所以用H表示
海中有大大小小的石头。石头很危险,所以用X表示
光相信自己一定能找到爱花(爱花的位置只有一种可能)
【输入格式】
第一行包括两个整数N,M。
接下来N行,每行M个字符。
【输出格式】
仅一行,表示爱花的位置(如果你无能为力,请输出 -1 ,只要你尽力,光不会责怪你)

【样例输入】
5 5
YYYHB
YYHHH
YHHXB
BBHBB
BBBBB
【样例输出】
2 3
【数据范围】
对于30%的数据,n,m<=10
对于70%的数据,n,m<=100
对于100%的数据,n,m<=300
【样例解释】
在(2,3)出现第一个H后,经过3s后,出现样例输入的地图。
P.S. Mushroom拜托他GF出的这题= =

正解与题解

Solution1
看了半天,什么也没发现。
天空突然电闪雷鸣,一个神奇的想法也就出现了。

YYYHB
YYHHH
YHHXB
BBHBB
BBBBB

这四个地方就是暖流的边界。
只有周围的四个格子是蓝蓝的大海或者石头和沙滩,才可能是暖流的边界。
我们可以把这些边界放进一个队列里,然后把图上变成大海。

YYYBB
YYHHB
YBHXB
BBBBB
BBBBB

然后就有了新的边界。
如此反复,最后剩下的暖流就是爱花的位置。

YYYBB
YYHBB
YBBXB
BBBBB
BBBBB

原来找到爱花这么容易。
时间复杂度O(N^2)
空间复杂度O(N^2)
恩,如果大海的结构这么简单的话,的确如此。
又看了半天,不得不佩服大海的深邃。

YYYHB
YYHHH
YHHXB
YXHXB
YYYYY

我们用之前的方法

YYYHB
YYHHH
YHHXB
YXHXB
YYYYY

放进队列,然后把它们变成大海

YYYBB
YYHHB
YHHXB
YXHXB
YYYYY

YYYBB
YYBBB
YHBXB
YXHXB
YYYYY

然后就成了这样,有两个位置看起来像是爱花所在的地方。
但事实并非如此。

YYYHB
YYHHH
YHHXB
YXHXB
YYYYY

爱花其实在这里。
Solution2
又想了半天。
看起来可以DP。
Flow[TIME][X][Y]表示暖流的初始位置是(X,Y),经过时间TIME以后,形成的图案会不会和海流图不相符(不应是H的地方出现了H则不相符,应出现H的地方没有出现H认为相符)

YYYHB
YYHHH
YHHXB
BBHBB
BBBBB

海流图

YYYBB
YYHHB
YBHXB
BBBBB
BBBBB

相符的图(蓝色部分应该出现H但没有出现)

YYYHH
YYHHH
YHHXH
BHHHB
BBHBB

不相符的图(红色部分不该出现H但出现了)
F[TIME][X][Y]=F[TIME-1][X-1][Y]&&F[TIME-1][X][Y-1]&&F[TIME-1][X+1][Y]&&F[TIME-1][X][Y+1]
记忆化DP 时间复杂度O(N^3) 空间复杂度 O(N^3)
找到最大的TIME,对应的X和Y就是爱花的位置。
因为光相信自己一定能找到爱花,所以爱花的位置确定(不会有两个位置满足条件)。
Solution3
更好的算法?
还得继续想吧。

code

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define PROB "calm"
#define MAXN 310
#define INF 0x3f3f3f3f
const int mov[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
typedef char mp_t[MAXN][MAXN];
typedef int dis_t[MAXN][MAXN];
int n,m;

mp_t mp;
dis_t dis1,dis2;
dis_t vis;
int vis_time=0;
int q[MAXN*MAXN][2];
void bfs1(dis_t &dis)
{
        int head=-1,tail=-1;
        int i,j,x,y;
        vis_time++;
        for (i=1;i<=n;i++)
        {
                for (j=1;j<=m;j++)
                {
                        if (mp[i][j]=='B')
                        {
                                vis[i][j]=vis_time;
                                q[++tail][0]=i;
                                q[tail][1]=j;
                                dis[i][j]=0;
                        }else if (mp[i][j]=='Y')
                                vis[i][j]=vis_time;
                }
        }
        int d;
        while (head<tail)
        {
                x=q[++head][0];
                y=q[head][1];
                d=dis[x][y];
                for (i=0;i<4;i++)
                {
                        x+=mov[i][0];
                        y+=mov[i][1];
                        if (x>0 && x<=n && y>0 && y<=m 
                                && vis[x][y]!=vis_time)
                        {
                                vis[x][y]=vis_time;
                                dis[x][y]=d+1;
                                q[++tail][0]=x;
                                q[tail][1]=y;
                        }
                        x-=mov[i][0];
                        y-=mov[i][1];
                }
        }
}
void bfs2(dis_t &dis,int x,int y)
{
        if (mp[x][y]!='H')throw 1;
        int head=-1,tail=0;
        q[0][0]=x;
        q[0][1]=y;
        dis[x][y]=0;
        vis_time++;
        vis[x][y]=vis_time;
        int i;
        int d;
        while (head<tail)
        {
                x=q[++head][0];
                y=q[head][1];
                d=dis[x][y];
                for (i=0;i<4;i++)
                {
                        x+=mov[i][0];
                        y+=mov[i][1];
                        if (x>0 && x<=n && y>0 && y<=m
                                && vis[x][y]!=vis_time
                                && mp[x][y]!='Y')
                        {
                                vis[x][y]=vis_time;
                                dis[x][y]=d+1;
                                q[++tail][0]=x;
                                q[tail][1]=y;
                        }
                        x-=mov[i][0];
                        y-=mov[i][1];
                }
        }
}
vector<pair<int,int> > vec;
int main()
{
        freopen(PROB".in","r",stdin);
        freopen(PROB".out","w",stdout);
        int i,j,k,x,y,z;
        scanf("%d%d\n",&n,&m);
        for (i=0;i<=n+1;i++)
                for (j=0;j<=m+1;j++)
                        mp[i][j]='Y';
        for (i=1;i<=n;i++)
        {
                fgets(mp[i]+1,sizeof(mp[i])-1,stdin);
                mp[i][m+1]='Y';//Pay attention of '\n' while using fgets()
        }
        int toth=0;
        for (i=1;i<=n;i++)
                for (j=1;j<=m;j++)
                {
                        if (mp[i][j]=='X')
                                mp[i][j]='Y';
                        if (mp[i][j]=='H')
                                toth++;
                }
        for (i=1;i<=n;i++)
        {
                for (j=1;j<=m;j++)
                {
                        if (mp[i][j]=='H' && mp[i-1][j]=='Y'
                                        && mp[i][j-1]=='Y' && mp[i+1][j]=='Y' && mp[i][j+1]=='Y')
                        {
                                if (toth==1)
                                        printf("%d %d\n",i,j);
                                else
                                        printf("-1\n");
                                return 0;
                        }
                }
        }
        bfs1(dis1);
        int mxdis=0,mx_x=-1,mx_y=-1;
        for (i=1;i<=n;i++)
        {
                for (j=1;j<=m;j++)
                {
                        if (dis1[i][j]>mxdis){
                                mxdis=dis1[i][j];
                                vec.clear();
                        }
                        if (dis1[i][j]==mxdis)
                        {
                                vec.push_back(make_pair(i,j));
                        }
                }
        }
        if (!vec.size())
        {
                printf("-1\n");
                return 0;
        }
        int ii;
        for (ii=0;ii<vec.size();ii++)
        {
                mx_x=vec[ii].first;
                mx_y=vec[ii].second;
                memset(dis2,INF,sizeof(dis2));
                bfs2(dis2,mx_x,mx_y);
                int mx=0,mn=INF;
                for (i=1;i<=n;i++)
                {
                        for (j=1;j<=m;j++)
                        {
                                if (mp[i][j]=='B')
                                        mn=min(mn,dis2[i][j]);
                                else if (mp[i][j]=='H')
                                        mx=max(mx,dis2[i][j]);
                        }
                }
                if (mx<mn)
                {
                        printf("%d %d\n",mx_x,mx_y);
                        return 0;
                }
        }
        {
                printf("-1\n");
        }
}

摘取某大神的比标答快了一个量级的代码;
ORZ膜拜……

欧皇随机数!

还是算了吧…………
本人都快怀疑我亚洲人的身份了……
(一脸黑……)

正经的随机数

考试时写了一个至少30分的随机数,测下来也如此,之后我就以此来讲诉如何正推
这里写图片描述

想法很简单,因为爱花的地址是唯一的,所以随机位置,后正推时间,完全协调时即为正解。
所以重点在判定协调

50分代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<stack>
#define rez(i,x,y) for(int i=x;i>=y;i--)
#define res(i,x,y) for(int i=x;i<=y;i++)
#define INF 2100000000
#define ll long long
#define clr(x)  memset(x,0,sizeof(x))
#define NAME "calm"
#define MAXN 100005

using namespace std;
int n,m,tim,op,tot,er;
char a[305][305];
struct data{
    int x,y;
};
data c[MAXN];
data e[MAXN];
bool b[MAXN];
int vis[305][305];
template <class T>
inline void read(T &x)
{
    x = 0;
    int flag = 1;
    char ch = getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch=='-') flag = -1;
        ch = getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x = (x<<1) + (x<<3) + ch-'0';
        ch = getchar();
    }
    x *= flag;
}
void judge(){
    int head=0,tail=1;
    while(head<tail&&op==0){
        int x=e[head].x,y=e[head].y;
        if(x<n)if(a[x+1][y]=='B')op=1;
        else if(a[x+1][y]=='H'&&vis[x+1][y]==0){vis[x+1][y]=1;tail++;
            e[tail].x=x+1,e[tail].y=y;
        }
        if(x>1)if(a[x-1][y]=='B')op=1;
        else if(a[x-1][y]=='H'&&vis[x-1][y]==0){vis[x-1][y]=1;tail++;
            e[tail].x=x-1,e[tail].y=y;
        }
        if(y<m)if(a[x][y+1]=='B')op=1;
        else if(a[x][y+1]=='H'&&vis[x][y+1]==0){vis[x][y+1]=1;tail++;
            e[tail].x=x,e[tail].y=y+1;
        }
        if(y>1)if(a[x][y-1]=='B')op=1;
        else if(a[x][y-1]=='H'&&vis[x][y-1]==0){vis[x][y-1]=1;tail++;
            e[tail].x=x,e[tail].y=y-1;
        }
        head++;
        if(tail>=tot)break;
    }
}
int main(){
    freopen(NAME".in","r",stdin);
    freopen(NAME".out","w",stdout);
    srand((unsigned)time(NULL));
    read(n);read(m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
            if(a[i][j]=='H'){
                c[++tot].x=i;   //处理每一个有可能为ans的点 
                c[tot].y=j; 
            }
        }
    }
    tot++;
    while(++er){
        int k=er;
        op=0;
        e[0].x=c[k].x;
        e[0].y=c[k].y;
        judge();
        if(!op){
            cout<<c[k].x<<' '<<c[k].y;
            return 0;
        }
        for(int i=0;i<=tot;i++){
            e[i].x=e[i].y=0;
        }
        memset(vis,0,sizeof(vis));
        er++;
        if(er>tot){cout<<"-1";return 0;}
    }
    return 0;
}

简单的枚举与暴力搜索,考虑情况不够成熟导致不能AC(并且卡时的方法也没有展现出来),但是比暴力给力很多了。
于是乎小便开始考虑是否可以用更大范围的随机跳点,毕尽十个点上诉代码只要0.04秒……
所以说如何AC?

随机数AC代码

这里写图片描述
车万
这里写图片描述
游戏王mugen
这里写图片描述
钉宫

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<stack>
#define rez(i,x,y) for(int i=x;i>=y;i--)
#define res(i,x,y) for(int i=x;i<=y;i++)
#define INF 2100000000
#define ll long long
#define clr(x)  memset(x,0,sizeof(x))
#define NAME "calm"
#define MAXN 100005
using namespace std;
struct node
{
    int x,y;
};
node v[100002];
char mp[302][302],c;
int n,m,sh,tot,l,r,st;
int qx[100002],qy[100002];
int vis[100002];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
bool sol(int o){
    qx[0]=v[o].x;
    qy[0]=v[o].y;
    vis[(v[o].x-1)*m+v[o].y]=o;
    l=0;
    r=1;
    st=1;
    int ss=1;
    while(l<r){
        for(int i=l;i<st;i++){
            for(int z=0;z<4;z++){
                int xx=qx[i]+dx[z];
                int yy=qy[i]+dy[z];
                if (mp[xx][yy]=='B')return 0;
                if (mp[xx][yy]=='H' && vis[(xx-1)*m+yy]!=o){
                    ss++;
                    qx[r]=xx;
                    qy[r]=yy;
                    r++;
                    vis[(xx-1)*m+yy]=o;
                }
            }
        }
        l=st;
        if(ss==sh)return 1;
        st=r;
    }
    return 0;
}
int main(){
    freopen(NAME".in","r",stdin);
    freopen(NAME".out","w",stdout);
    cin>>n>>m;
    memset(mp,'X',sizeof(mp));
    sh=0;
    tot=0;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++){
            c=getchar();
            while (c!='X' && c!='Y' && c!='B' && c!='H') c=getchar();
            mp[i][j]=c;
            if (c=='H')
            {
                sh++;
                v[tot].x=i;
                v[tot].y=j;
                tot++;
            }
        }
    }
    memset(vis,-1,sizeof(vis));
    srand((unsigned)time(NULL));
    for (int i=0;i<tot;i++){
        if(sol(i)==1){
            cout<<v[i].x<<' '<<v[i].y;
            return 0;
        }
    }
    printf("-1\n");
    return 0;
}

随机数最好是暴力的利用工具,而不是以随机数来决定答案。
即以随机状态找寻答案。
今天就到这里吧……
有兴趣的读者可以催催更,博主现高一信竞党,若有错误,请多指教,谢谢。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值