[蓝桥杯 2013 省 A] 剪格子(DFS)

 题目传送门

 题目主要需要理解的是第二个样例和“包含左上角的分割区可能包含的最小的格子数目”这句话,其实结合第二个样例,意思就是:对第二个样例而言可以输出2也可以输出10,不过题目要求输出包含左上角元素的结果,所以答案是10

思路分析1:

这里我的思路是采用暴力搜索解决,首先确定我们从左上角作为起点开始搜索,其次是枚举需要切割的格子数量,这里因为需要分割成2部分,所以最大我们可以切割的格子数量是n*m-1,最后设定搜索出口是叠加切割的格子元素后是否等于所有格子元素之和的一半即可 

因为这里每次需要切割的格子数是从小到大找的,所以得到的答案自然是最小的

#include<iostream>
#include<cstdlib>
#define MAX 15
using namespace std;

int m, n ,all=0;
int map[MAX][MAX];
int visited[MAX][MAX];
int nextt[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };	

void dfs(int x, int y,int step,int endd, int sum) {//step代表现在已经得到格子数
	if (step == endd) {//剪取的格子数够了//endd代表本次搜索需要切割多少格子数
		if (all - sum == sum) {         //sum代表已经切割格子元素之和
			cout << endd << endl;
			exit(0);
		}
	}
	else {
		for (int i = 0; i < 4; i++) {
			int tx = x + nextt[i][0];
			int ty = y + nextt[i][1];
			if (tx < 0 || ty < 0 || tx == n || ty == m || visited[tx][ty]) {
				continue;
			}
			visited[tx][ty] = true;
			dfs(tx, ty, step + 1, endd, sum + map[tx][ty]);
			visited[tx][ty] = false;
		}
	}
}


int main()
{
	int sum;
	cin >> m >> n;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> map[i][j];
			all += map[i][j];
		}
	}
	sum = n * m - 1;
	for (int i = 1; i <= sum; i++) {//枚举每次剪取的格子数
		memset(visited, false, sizeof(visited));
		visited[0][0] = true;
		dfs(0, 0,1, i,map[0][0]);//(0,0)每次都从左上角开始
	}
	cout << 0 << endl;
	return 0;
}

 下面是我看到的另外一篇比较好的题解,分享一下

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
int n,m,sum,minn=INT_MAX,a[15][15];
bool vis[15][15],flag;
inline bool check(int x,int y){return x>0&&x<=m&&y>0&&y<=n;}//特判要注意了,我就在这里被坑了
inline void dfs(int x,int y,int cnt,int now){
	if((now<<1)==sum)minn=min(minn,cnt);//取最小值
	else if((now<<1)>sum);//已经大于就不用搜了,小优化
	else{
		for(int i=0;i<4;i++){
			int nx=x+dx[i],ny=y+dy[i];//向四个方向搜索
			if(check(nx,ny)){
				if(!vis[nx][ny]){
					vis[nx][ny]=1;
					dfs(nx,ny,cnt+1,now+a[nx][ny]);
					vis[nx][ny]=0;//记得回溯
				}
			} 
		}
	}
}
signed main(){
	cin>>n>>m;
	vis[1][1]=1;
	for(int i=1;i<=m;i++)for(int j=1;j<=n;j++)cin>>a[i][j],sum+=a[i][j];
	dfs(1,1,1,a[1][1]);
	if(minn^INT_MAX)cout<<minn<<endl;
	else puts("0");//无解
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZZZWWWFFF_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值