搜索专题练习

T1:狗哥玩木棒

现给出一些木棒长度,那么狗哥能否用给出的木棒(木棒全用完)组成一个正方形呢?

思路:

既然已经规定木棒全都用上,那么边长就已经定下,就是周长的四分之一

那么只要考虑剪枝和细节模拟就好了

同时,我们对木棒进行排序,保证木棒长度有序,短的木棒可以对长的进行填充,进行极大的优化

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=25;
int n,m;
int a[N];
bool used[N],ok;
int sum;
inline void clear(){
	memset(used,0,sizeof used);
	sum=0;
	ok=0;
}
inline bool cmp(const int &a,const int &b){
	return a>b;
}
inline void search(int pos,int now){
	if(ok||now>sum) return ;
	if(now==sum) {now=0;++pos;}
	if(pos==4) {printf("yes\n");ok=1;}
	for(int i=1;i<=m;++i){
		if(!used[i]){
			used[i]=1;
			search(pos,now+a[i]);
			used[i]=0;
			if(!now||!(now+a[i])) return ;
		}
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		clear();
		scanf("%d",&m);
		for(int i=1;i<=m;++i) {scanf("%d",&a[i]);sum+=a[i];}
		sum/=4;
		sort(a+1,a+1+m,cmp);
		search(0,0);
		if(!ok) printf("no\n");
	}
}

T2:骑马修栅栏

John 是一个与其他农民一样懒的人。他讨厌骑马,因此从来不两次经过一个栅栏。

John 的农场上一共有 m 个栅栏,每一个栅栏连接两个顶点,顶点用 1 到 500 标号(虽然有的农场并没有那么多个顶点)。一个顶点上至少连接 1 个栅栏,没有上限。两顶点间可能有多个栅栏。所有栅栏都是连通的(也就是你可以从任意一个栅栏到达另外的所有栅栏)。John 能从任何一个顶点(即两个栅栏的交点)开始骑马,在任意一个顶点结束。

你需要求出输出骑马的路径(用路上依次经过的顶点号码表示),使每个栅栏都恰好被经过一次。如果存在多组可行的解,按照如下方式进行输出:如果把输出的路径看成是一个 500 进制的数,那么当存在多组解的情况下,输出 500 进制表示法中最小的一个 (也就是输出第一位较小的,如果还有多组解,输出第二位较小的,以此类推)。

输入数据保证至少有一个解。

思路:

考虑每个点与路径(栅栏)的联系,可以帮助处理题目

在这种"一笔画问题"中,统计"奇点数"是一种即为广泛的做法

结合代码理解:

#include<iostream>
#include<cstdio>
#define ci const int &
using namespace std;
const int N=505;
int n,cnt;
int f[N][N],in[N];
int rd[N];
int maxn;
inline void search(ci now){
	for(int i=1;i<=maxn;++i)
		if(f[now][i]) {--f[now][i]; --f[i][now]; search(i);}
	rd[++cnt]=now;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		int a,b;
		scanf("%d%d",&a,&b);
		++f[a][b]; ++f[b][a];
		++in[a]; ++in[b];
		maxn=max(max(a,b),maxn);
	} int s=1;
	for(int i=1;i<=maxn;++i){
		if(in[i]%2){
			s=i;
			break;
		}
	} search(s);
	for(int i=cnt;i>=1;--i)
		printf("%d\n",rd[i]);
	return 0;
}
posted @ 2020-04-11 12:00  _Alex_Mercer  阅读(165)  评论(0编辑  收藏  举报