Rats codeforces 254D

【原题地址】: codeforces254D

【题目大意】:

你有两个炸弹,每个炸弹只能炸到与炸弹相距 \(d\) (曼哈顿距离)的老鼠,问在哪两个点放炸弹,能炸死所有老鼠(炸弹不能都放在一个位置),若不能输出 \(-1\)

【题解】:

我们首先可以知道,\(d\) 的范围比较小,当老鼠过多时就炸不完了,所以当老鼠个数大于 \(290\) 时直接输出 \(-1\)
我们对每只老鼠所在的位置进行 \(bfs\) 向外扩展 \(d\) 格,对于搜到的每个点进行编号,并且记录这个点能炸到哪些老鼠
处理完过后直接枚举,输出答案
如下
va[num][k] 数组用于记录 \(num\) 号点能否炸到第 \(k\) 只老鼠
vx[num] vy[num] 分别用于记录 \(num\) 号点的坐标
reach[x][y] 表示点 \((x,y)\) 有没有进行重新编号

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int max_rats=290;
const int maxn=1000+10;
struct node
{
    int x,y,d;
    node(int xx=0,int yy=0,int dd=0){
        x=xx,y=yy,d=dd;
    };
};
vector<node>rats;
int n,m,d,cnt_rats=0,size=0;
int map[maxn][maxn];
char s[maxn][maxn];
int reach[maxn][maxn];
int vx[max_rats*max_rats],vy[max_rats*max_rats];
bool va[max_rats*max_rats][max_rats];
bool vis[maxn][maxn];
const int dx[4]={0,1,-1,0},dy[4]={1,0,0,-1};
void put_set(int x,int y,int type)//(x,y)能炸到type号老鼠
{
    if(!reach[x][y])//未编过号
    {
        va[++size][type]=1;
        vx[size]=x;
        vy[size]=y;
        return ;
    }
    for(int i=1;i<=size;i++)
    if(vx[i]==x&&vy[i]==y){
        va[i][type]=1;
        break;
    }
}
void bfs(int type,node st)//对每只老鼠进行处理
{
    memset(vis,0,sizeof(vis));
    queue<node>q;
    q.push(st);
    vis[st.x][st.y]=1;
    while(!q.empty())
    {
        node u=q.front();
        q.pop();
        put_set(u.x,u.y,type);
        reach[u.x][u.y]=1;
        if(u.d==d)continue;
        for(int i=0;i<4;i++)
        {
            int x=u.x+dx[i],y=u.y+dy[i];
            if(x<1||x>n||y<1||y>m||vis[x][y]||map[x][y])continue;
            vis[x][y]=1;
            q.push(node(x,y,u.d+1));
        }
    }   
}
int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    int ans1,ans2,find_ans=0;
    scanf("%d%d%d",&n,&m,&d);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s[i]+1);
        for(int j=1;j<=m;j++)
        if(s[i][j]=='R')cnt_rats++;
    }
    if(cnt_rats>max_rats){printf("-1\n");return 0;}
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        map[i][j]=0;
        if(s[i][j]=='X')map[i][j]=1;
        if(s[i][j]=='R')rats.push_back(node(i,j,0));
    }
    for(int i=0;i<cnt_rats;i++)
    bfs(i,rats[i]);
    if(size==1)//只有一个点能炸到老鼠
    {
        for(int i=0;i<cnt_rats;i++)
        if(va[1][i]==0)
        {
            printf("-1\n");
            return 0;
        }
        printf("%d %d ",vx[1],vy[1]);
        for(int i=1;i<=n;i++)//寻找一个与之前点不同的点
        for(int j=1;j<=m;j++)
        {
            if(map[i][j]||(i==vx[1]&&j==vy[1]))continue;
            printf("%d %d\n",i,j);
            return 0;
        }
    }
    for(int i=1;i<size;i++)
    {
        
        for(int j=i+1;j<=size;j++)//枚举能炸到老鼠的两个不同的点
        {
            find_ans=1;
            for(int k=0;k<cnt_rats;k++)
            if(va[i][k]==0&&va[j][k]==0)//有一只老鼠不能炸到
            {
                find_ans=0;
                break;
            }
            if(find_ans){
                ans1=i;
                ans2=j;
                break;
            }
        }   
        if(find_ans)break;
    }
    if(find_ans)printf("%d %d %d %d\n",vx[ans1],vy[ans1],vx[ans2],vy[ans2]);
    else printf("-1\n");
}

转载于:https://www.cnblogs.com/Harry-bh/p/8831848.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值