搜索专题练习
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;
}