题解 P2105 【K皇后】

· · 题解

感觉我的可能是最简洁明了的了

简述一下思路

一行一行扫,如果当前行有国王直接跳过,否则遍历每个国王,每个国王对当前行有三个影响,一是对当前行和他列数相同的格子有攻击,二是他所占有的两条对角线可能会攻击到当前格子,这里要判断一下对角线延伸到当前行列数是否越界(在1-m中间),使用一个flag数组标记当前行每个位置是否被攻击到,每行遍历时开一个sum每次初始化为m,如果当前循环中已经没有被攻击过就sum--。

看到有人用memset每次清空flag,这里不需要,我们可以把flag定义为int类型,然后用当前行数作为标记,如果flag[i]不等于当前行数那就是没有攻击过,然后把这个位置的值赋成当前行的行数。

这样复杂度就是严格o(n*k),完全可以接受。

代码如下,比较短

#include<bits/stdc++.h>
using namespace std;
int x[501],y[501],n,m,k;
int flag[20001],vis[20001],sum,ans;
int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=k;i++) cin>>x[i]>>y[i],vis[x[i]]=1;
    for(int i=1;i<=n;i++)
    {
        if(vis[i]) continue;//当前行有国王直接跳过
        sum=m;
        for(int j=1;j<=k;j++)
        {
            if(flag[y[j]]!=i) sum--;//当前国王控制的列数
            flag[y[j]]=i;
            if(x[j]<i)//当前国王在当前行上方
            {
                if(y[j]+i-x[j]>=1&&y[j]+i-x[j]<=m) 
                {//右下方向对角线
                    if(flag[y[j]+i-x[j]]!=i) sum--;
                    flag[y[j]+i-x[j]]=i;
                }
                if(y[j]-i+x[j]>=1&&y[j]-i+x[j]<=m) 
                {//左下方向对角线
                    if(flag[y[j]-i+x[j]]!=i) sum--;
                    flag[y[j]-i+x[j]]=i;
                }
            }
            else //当前国王在当前行下方
            {
                if(y[j]+(x[j]-i)>=1&&y[j]+(x[j]-i)<=m)
                {//右下方向对角线
                    if(flag[y[j]+(x[j]-i)]!=i) sum--;
                    flag[y[j]+(x[j]-i)]=i;
                }
                if(y[j]-(x[j]-i)>=1&&y[j]-(x[j]-i)<=m)
                {//左下方向对角线
                    if(flag[y[j]-(x[j]-i)]!=i) sum--;
                    flag[y[j]-(x[j]-i)]=i;
                }
            }
        }
        ans+=sum;
    }
    cout<<ans;
 }