1. 程式人生 > >題解 U22784 【yizimi的玄學炸彈人】

題解 U22784 【yizimi的玄學炸彈人】

題目連結:https://www.luogu.org/problemnew/show/U22784

題目

題目背景

yizimi最近喜歡玩一個很玄學的炸彈人遊戲

題目描述

在一張n × m(2<n,m<=5000)的地圖上,‘#’表示牆,‘*’表示敵人,‘.’表示空地(可以通過或安放炸彈),給出yizimi所在的初始位置(startx,starty),他只可放一顆炸彈,炸彈威力極大,可以同時炸死同一列,同一行的敵人,不過不能穿牆(牆後的敵人炸不死(霧))。問他可以去哪裡放炸彈,使得炸死的敵人最多?最多多少?

注意:yizimi不可以往敵人身上撞喲!

感謝涼涼提供資料支援!!!

輸入輸出格式

輸入格式:

第一行:n , m , startx , starty。分別指地圖行數、列數、初始位置的座標 第2~n+1行:輸入m個字元,指地圖。

輸出格式:

第一行輸出座標,用空格空開 第二行輸出最多炸死的敵人

說明

20%資料滿足:2<n,m<=10

100%資料滿足:2<n,m<=5000

總滿足1<startx,starty<n

總滿足地圖最外層為牆

保證yizimi炸死最多的方案唯一(不限定做法)

不保證yizimi可以去到所有空地

題目分析

首先,這是一組迷宮題,別看資料很大,m,n都能到5000,實際上因為只求連通的面積中的大小,直接爆搜就可以了。

演算法精析

1.求一個點可以炸死多少敵人

其實就是上下左右四個方向,只要炸到牆,就停止。一個方向的程式碼如下:

x=i;y=j;//這句話千萬別忘了!!!否則就會算成其他行的敵人數
while(a[x][y]!='#'){
    if(a[x--][y]=='*'){//向左的,其餘變變方向即可
        sum++;
    } 
} 

2.求連通

用一個DFS去求連通(BFS一樣OK啦),每次前進順便把結果計算一下。

void dfs(int x,int y){
    int tx,ty,k,sum;
    sum=_num(x,y);
    if(sum>maxx){
        maxx=sum;
        mx=x;
        my=y; 
    } 
    for(k=1;k<=4;k++){
        tx=x+next[k][0];
        ty=y+next[k][1];
        if(tx<1 || tx>n || ty<1 || ty>m ){
            continue;
        } 
        if(a[tx][ty]=='.' && !book[tx][ty]){
            book[tx][ty]=1;
            dfs(tx,ty);
        }
    } 
    return;
}

完整程式碼

有我自己的程式碼習慣,勿噴
和上面程式碼有些不同,其實等效

#include<iostream>
#include<string>
#include<iostream>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define mn 5010 
char a[mn][mn];
int book[mn][mn]={0};
int maxx,mx,my,n,m;
int next[5][2]={{0,0},{0,1},{1,0},{0,-1},{-1,0}};
inline int _num(int i,int j){
    int sum=0,x,y;
    x=i;y=j;
    while(a[x][y]!='#')
        if(a[x--][y]=='*')
            sum++;
    x=i;y=j;
    while(a[x][y]!='#')
        if(a[x++][y]=='*')
            sum++;
    x=i;y=j;
    while(a[x][y]!='#')
        if(a[x][y--]=='*')
            sum++;
    x=i;y=j;
    while(a[x][y]!='#')
        if(a[x][y++]=='*')
            sum++;
    return sum;
}
inline void dfs(int x,int y){
    int tx,ty,k,sum;
    sum=_num(x,y);
    if(sum>maxx)
        maxx=sum,mx=x,my=y; 
    go(k,1,4,1){
        tx=x+next[k][0];
        ty=y+next[k][1];
        if(tx<1 || tx>n || ty<1 || ty>m )
            continue;
        if(a[tx][ty]=='.' && !book[tx][ty])
            book[tx][ty]=1,dfs(tx,ty);
    } 
    return;
}
int main(){
    int i,j,startx,starty;
    //freopen("yizimi001.in","r",stdin); 
    cin>>n>>m>>startx>>starty;
    go(i,1,n,1)
        go(j,1,m,1)
            cin>>a[i][j];
    book[startx][starty]=1;
    maxx=_num(startx,starty);
    mx=startx,my=starty;
    dfs(startx,starty); 
    cout<<mx<<" "<<my<<"\n";
    cout<<maxx; 
    return 0;
}