m皇后(思路题目)

119 篇文章 1 订阅
113 篇文章 1 订阅

这道题当初有两点没有想到,一点是不知道该如何处理斜着的方向,另一点是没想到只用求该直线上的两端点。

这题要开四个数组,分别记录该方向上的点的最左端和最右端。
然后遍历所有的点,遍历该点的四个方向(上下是一个方向,左右是一个方向,斜向上一个,斜向下一个),如果该方向上只有一个点,就不存在威胁,如果该点在最右端或者最左端,在该方向上就有一个威胁,否则该点在中间,就有两个威胁。然后记录该点有几个威胁。

忘了一点,如何判断斜方向的范围:
斜方向的斜率都是1或者-1,所以都满足y=x+b(或者y=-x+b),这样同一斜线上的y-x(或者y+x)的值是固定的,b就是判断条件,只需注意y-x为负数的时候就行了。

思想:
记录四个方向的点的分布范围(左右最值);
遍历每个点判断每个点的威胁个数。

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=100009;

int xx[maxn][2];//以行为直线,纵坐标的分布,xx[][0]为最小值,xx[][1]为最大值,
int yy[maxn][2];//以列为直线,横坐标的分布,
int yx[maxn*2][2];//y=-x+b的直线的点的分布,
int y_x[maxn][4];//y=x+b的直线的点的分布,0,1记录y-x为正的最小值和最大值,2,3记录y-x为负的最小值和最大值
int ans[10];//ans[i]记录i个威胁的点的个数
int a[maxn],b[maxn];//记录横纵坐标
int main()
{
    int n,m,x,y;
    while(~scanf("%d%d",&n,&m))
    {
        memset(ans,0,sizeof(ans));//初始化
        memset(xx,0,sizeof(xx));
        memset(yy,0,sizeof(yy));
        memset(yx,0,sizeof(yx));
        memset(y_x,0,sizeof(y_x));
        for(int i=0; i<m; i++)
        {
            scanf("%d%d",&x,&y);
            a[i]=x,b[i]=y;
            if(xx[x][0]==0)//以行为直线
                xx[x][0]=xx[x][1]=y;
            else
            {
                xx[x][0]=min(xx[x][0],y);
                xx[x][1]=max(xx[x][1],y);
            }
            if(yy[y][0]==0)//以列为直线
                yy[y][0]=yy[y][1]=x;
            else
            {
                yy[y][0]=min(yy[y][0],x);
                yy[y][1]=max(yy[y][1],x);
            }
            int f1=y+x;
            int f2=y-x;
            if(yx[f1][0]==0)//以y=-x+b为直线
                yx[f1][0]=yx[f1][1]=y;
            else
            {
                yx[f1][0]=min(yx[f1][0],y);
                yx[f1][1]=max(yx[f1][1],y);
            }
            if(f2>=0)//以y=x+b为直线,且y-x>=0时
            {
                if(y_x[f2][0]==0)
                    y_x[f2][0]=y_x[f2][1]=y;
                else
                {
                    y_x[f2][0]=min(y_x[f2][0],y);
                    y_x[f2][1]=max(y_x[f2][1],y);
                }
            }
            else
            {
                f2=-f2;
                if(y_x[f2][2]==0)
                    y_x[f2][2]=y_x[f2][3]=y;
                else
                {
                    y_x[f2][2]=min(y_x[f2][2],y);
                    y_x[f2][3]=max(y_x[f2][3],y);
                }
            }
        }
        for(int i=0; i<m; i++)
        {
            int sum=0;
            x=a[i],y=b[i];
            int f1=x+y,f2=y-x;
            if(xx[x][0]==xx[x][1]);//横向
            else if(xx[x][0]==y||xx[x][1]==y)
                sum++;
            else sum+=2;
            if(yy[y][0]==yy[y][1]);//纵向
            else if(yy[y][0]==x||yy[y][1]==x)
                sum++;
            else sum+=2;
            if(yx[f1][0]==yx[f1][1]);//斜向下
            else if(yx[f1][0]==y||yx[f1][1]==y)
                sum++;
            else sum+=2;
            if(f2>=0)//斜向上
            {
                if(y_x[f2][0]==y_x[f2][1]);
                else if(y_x[f2][0]==y||y_x[f2][1]==y)
                    sum++;
                else sum+=2;
            }
            else
            {
                f2=-f2;
                if(y_x[f2][2]==y_x[f2][3]);
                else if(y_x[f2][2]==y||y_x[f2][3]==y)
                    sum++;
                else sum+=2;
            }
            ans[sum]++;//个数加一
        }
        for(int i=0; i<8; i++)//输出
            printf("%d ",ans[i]);
        printf("%d\n",ans[8]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值