连通块 dfs 模拟战役

本文介绍了一种使用BFS和DFS寻找连通块的方法,应用于解决特定的棋盘问题。代码实现中,BFS用于查找司机大炮的连通块,DFS或BFS(简化为bf2)用于查找齐齐大炮的连通块。通过比较两者连通块数量和大炮数,实现一种贪心策略,找到最优解。博客还提及了计数技巧和代码优化,适合理解搜索算法和连通块问题。
摘要由CSDN通过智能技术生成

题目:

链接:登录—专业IT笔试面试备考平台_牛客网
bfs版:

#include<bits/stdc++.h>
using namespace std;
int m,se=0;
char mas[10][110];
bool vis[10][110]={0};
int cnt1=0,cnt[500]={0},ans=0;
int dir[][4]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,-1},{1,-1},{-1,1}};
inline void bfs(int X,int Y){
    queue<pair<int,int> >s;
    s.push(make_pair(X,Y));
    vis[X][Y]=1;
    while(!s.empty()){
        int x=s.front().first,y=s.front().second;s.pop();
        for(int i=0;i<8;++i){
            int xx=x+dir[i][0],yy=y+dir[i][1];
            if(xx&&xx<=4&&yy&&yy<=m){
                if(!vis[xx][yy]&&mas[xx][yy]=='*'){
                    vis[xx][yy]=1;s.push(make_pair(xx,yy));
                }
            }
        }
    }
}
inline int bf2(int X,int Y){
    queue<pair<int,int> >s;
    s.push(make_pair(X,Y));
    vis[X][Y]=1;int ans=0;
    while(!s.empty()){
        int x=s.front().first,y=s.front().second;s.pop();++ans;
        for(int i=0;i<8;++i){
            int xx=x+dir[i][0],yy=y+dir[i][1];
            if(xx>4&&xx<=8&&yy&&yy<=m){
                if(!vis[xx][yy]&&mas[xx][yy]=='*'){
                    vis[xx][yy]=1;s.push(make_pair(xx,yy));
                }
            }
        }
    }
    return ans;
}
int main()
{
	cin>>m;
	for(int i=1;i<=8;++i){
		for(int j=1;j<=m;++j) cin>>mas[i][j];
	}
	for(int i=1;i<=4;++i){//司机大炮 
		for(int j=1;j<=m;++j){
			if(mas[i][j]=='*'&&!vis[i][j]){
			bfs(i,j);
			++cnt1;
		}
		}
	}
	for(int i=5;i<=8;++i){//齐齐的大炮 
		for(int j=1;j<=m;++j){
			if(mas[i][j]=='*'&&!vis[i][j]){
				//bfs2(i,j);
				cnt[++cnt[0]]=bf2(i,j);
			}
		}
	}
	if(cnt[0]<cnt1){
		cout<<-1<<endl;
		return 0;
	}
	sort(cnt+1,cnt+1+cnt[0]);
	int sd=0;
	for(int i=cnt1;i<=cnt[0];++i){
		sd+=cnt[i];
	}
	cout<<sd<<endl;
	return 0;
	
}

就是分两次搜索,找出所有连通块,齐齐跟司机的连通块永远是一换一(除了最后一轮,齐齐直接把司机打没了),所以一个简单贪心,每次用连通块内大炮数最少的连通块去跟司机极限一换一,最后那些多出来的,就是答案了。

for(int i=5;i<=8;++i){//齐齐的大炮 
		for(int j=1;j<=m;++j){
			if(mas[i][j]=='*'&&!vis[i][j]){
				//bfs2(i,j);
				cnt[++cnt[0]]=bf2(i,j);
			}
		}
	}
	if(cnt[0]<cnt1)

这里的计数方式是我刚学的,cnt[0]用来记录连通块数,cnt[i]记录每个连通块的大炮数。其实也只是少定义了一个sum,但是感觉挺装逼的哈哈哈哈哈。

当然也可以用dfs,思路是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值