「 「 「基础算法 」 」 」第 4 4 4章 深度搜索
目录:
A.拔河比赛
B.数独游戏
C.虫食算
A . A. A. 例题 1 1 1 拔河比赛
分析:
对于每个人 只需要看这个人加在一队好还是二队
所以直接搜就行啦 ( ? (? (? ? ? ? ? ) ?) ?)
然后取 m i n min min即可.
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
int T,n,a[100005],ans;
inline void dfs(int dep,int num1,int que1,int num2,int que2) //dfs
{
if(dep>n)
{
if(abs(num1-num2)<=1) //条件
ans=min(ans,abs(que1-que2)); //取最小
return;
}
dfs(dep+1,num1+1,que1+a[dep],num2,que2); //分别加入一队
dfs(dep+1,num1,que1,num2+1,que2+a[dep]); //二队
}
int main(){
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(reg int i=1;i<=n;i++)
scanf("%d",&a[i]);
ans=1e8;
dfs(1,0,0,0,0);
printf("%d\n",ans);
}
return 0;
}
B . B. B. 例题 2 2 2 数独游戏
分析:
用三个数组 分别存储:行 列 九宫格当前格子数字的状态
然后模拟 1 1 1~ 9 9 9数字填写 即可.
洛谷上改改输入即可.
具体填数字: d f s dfs dfs解决
把 9 ∗ 9 9*9 9∗9大矩阵分成 9 9 9个 3 ∗ 3 3*3 3∗3的小矩阵来填
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
string s;
const int N=15;
int a[N][N],x[N][N],y[N][N],f[5][5][N],out;
void pre()
{
out=0;
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(f,0,sizeof(f));
}
int val(int x)
{
if(x<4) return 1;
if(x<7) return 2; //分成小矩阵
return 3;
}
bool check(int q,int b,int c)
{
if(!x[q][c]&&!y[b][c]&&!f[val(q)][val(b)][c]&&a[q][b]==0) return 1;
else return 0;
}
void dfs(int xx,int yy) //模拟填数字
{
if(out) return;
if(xx>9)
{
for(reg int i=1;i<=9;i++)
for(reg int j=1;j<=9;j++)
printf("%d",a[i][j]);
printf("\n");
out=1; return;
}
if(a[xx][yy])
{
if(yy==9) dfs(xx+1,1);
else dfs(xx,yy+1);
}
for(reg int i=1;i<=9;i++)
{
if(check(xx,yy,i))
{
a[xx][yy]=i;
x[xx][i]=y[yy][i]=f[val(xx)][val(yy)][i]=1; //标记
if(yy==9) dfs(xx+1,1);
else dfs(xx,yy+1);
a[xx][yy]=0;
x[xx][i]=y[yy][i]=f[val(xx)][val(yy)][i]=0;
}
}
}
int main(){
while(cin>>s)
{
if(s=="end ") return 0;
pre();
for(reg int i=1;i<=9;i++)
for(reg int j=1;j<=9;j++)
{
if(s[(i-1)*9+j-1]!='.')
{
a[i][j]=s[(i-1)*9+j-1]-'0'; //转换数字
x[i][a[i][j]]=1;
y[j][a[i][j]]=1;
f[val(i)][val(j)][a[i][j]]=1;
}else a[i][j]=0;
}
dfs(1,1);
}
return 0;
}
C . C. C. 例题 3 3 3 虫食算
分析:
考虑从低位到高位不断填已经确定的数
但是不能把不确定的数都试一遍 会超时
那么我们每确定一个数 就把已知式子和未知进位的式子试一遍
如果当前这一列三个值都试过 就加法进位
否则 如果没进位 看 ( a + b ) (a+b) (a+b)的最低位是否 = c =c =c 有进位就看 ( a + b + 1 ) (a+b+1) (a+b+1)的最低位是否 = c =c =c
最后一直 d f s dfs dfs就可以了.
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
const int N=35;
string s[4];
int n,ans[N],turn[N],num;
bool vis[N],ok;
inline void print()
{
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
ok=1;
exit(0);
}
inline bool check()
{
int add=0;
for(reg int i=n;i>0;i--)
{
int a=ans[s[1][i-1]-'A'+1],b=ans[s[2][i-1]-'A'+1],c=ans[s[3][i-1]-'A'+1];
if(a!=-1&&b!=-1&&c!=-1)
{
if(add!=-1) //没进位
{
if((a+b+add)%n!=c) return false; //判断不合法
if(i==1&&(a+b+add)/n) return false;
add=(a+b+add)/n; //赋值进位
}else
{
if((a+b)%n!=c&&(a+b+1)%n!=c) return false; //有进位情况
if(i==1&&(a+b)/n) return false;
}
} else add=-1;
}
return true;
}
inline void dfs(int x)
{
if(ok) return;
if(x>n) print();
for(reg int i=0;i<n;i++)
{
if(!vis[i])
{
vis[i]=1;
ans[turn[x]]=i;
if(check()) dfs(x+1); //dfs填数
vis[i]=0;
ans[turn[x]]=-1;
}
}
}
int main(){
scanf("%d",&n);
cin>>s[1]>>s[2]>>s[3];
for(reg int i=n-1;i>=0;i--)
for(reg int j=1;j<=3;j++)
if(!vis[s[j][i]-'A'+1])
{
vis[s[j][i]-'A'+1]=1;
turn[++num]=s[j][i]-'A'+1; //转化
}
memset(vis,0,sizeof(vis));
memset(ans,-1,sizeof(ans));
dfs(1);
return 0;
}