前情详见 dfs+search
T1:拔河比赛
拔河比赛两边人数最多不能相差1 。 每个队员都有体重,我们要使两边比赛的人体重和相差最小。 现在有 n 个队员,韩老师想你帮忙分配,并且把分配后两边体重和之差最小值输出。
其实挺暴力的,要把每一种分配方式的体重差都求出来取最小值
#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
int T,n,w[100010],s,ans=1e9;
void dfs(int x,int y,int z)//位置 人数 总重
{
if(y==n/2)
{
ans=min(ans,abs(s-z*2));
}
if(x>n)return;
dfs(x+1,y+1,z+w[x]);
dfs(x+1,y,z);
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
s=0;
ans=9999999;
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
s+=w[i];
}
dfs(1,0,0);
printf("%d\n",ans);
}
return 0;
}
T2:数独游戏
数独的性质就是同一行、同一列、同一九宫格内,一种数字只能填一次,那么这时候就可以记一下当前这格所在行、列、九宫格的状态(显然要状压),再看这一格能填什么,填不上任何数就不再搜索下去。以及每轮填数的时候优先填选择少的,能少出现一些非法情况
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
string s;
bool flag;
int a[10][10];
int f[10][10], f1[10][10], f2[10][10];
int dg[10]={0, 1, 1, 1, 2, 2, 2, 3, 3, 3};
void dfs(int x, int y)
{
if(flag) return;
if(x>9)
{
flag=1;
for(int j=1; j<=9; j++)
for(int i=1; i<=9; i++)
printf("%d", a[i][j]);
return;
}
if(a[x][y]!=0)
{
if(y==9) dfs(x+1, 1);
else dfs(x, y+1);
}
int d;
if(x<=3) d=dg[y];
else if(x<=6) d=3+dg[y];
else d=6+dg[y];
for(int i=1; i<=9; i++)
{
if(f[x][i]==1||f1[y][i]==1||f2[d][i]==1||a[x][y]!=0) continue;
f[x][i]=1;
f1[y][i]=1;
f2[d][i]=1;
a[x][y]=i;
if(y==9) dfs(x+1, 1);
else dfs(x,y+1);
f[x][i]=0;
f1[y][i]=0;
f2[d][i]=0;
a[x][y]=0;
}
}
int main()
{
cin>>s;
while(s!="end")
{
flag=0;
for(int j=1; j<=9; j++)
for(int i=1; i<=9; i++)
if(s[(j-1)*9+i-1]!='.') a[i][j]=s[(j-1)*9+i-1]-48;
for(int i=1; i<=9; i++)
for(int j=1; j<=9; j++)
{
f[i][a[i][j]]=1;
f1[j][a[i][j]]=1;
if(i<=3) f2[dg[j]][a[i][j]]=1;
else if(i<=6) f2[3+dg[j]][a[i][j]]=1;
else f2[6+dg[j]][a[i][j]]=1;
}
dfs(1, 1);
cout<<endl;
cin>>s;
memset(f, 0, sizeof(f));
memset(f1, 0, sizeof(f1));
memset(f2, 0, sizeof(f2));
memset(a, 0, sizeof(a));
}
return 0;
}
T3:虫食算
虽然知道应该不太能一次AC,但也万万没想到首次提交才 30pts。其中注释掉的代码均为剪枝.......整体流程大概是依次枚举哪个字母对应哪个数字,从右往左一列一列扫,别忘了进位。期间分两钟情况:
- 右侧所有字母均已确定,可知进位是多少
- 有字母未知,进位为一或0。
另外对于最高位而言,有进位是不合法的,因为题目要求生成数字也是 n 位数。
#include<bits/stdc++.h>
using namespace std;
int n,num[31];
char s[4][31];
bool vis[31];
void dfs(int x,int y,int w){
int c,c1,c2,c3;
if(!x){
if(!w){
for(int i=1;i<n;i++) printf("%d ",num[i]);
printf("%d\n",num[n]);
exit(0);
}
return;
}
for(int i=x-1;i>=1;i--){
c1=num[s[1][i]-'A'+1];
c2=num[s[2][i]-'A'+1];
c3=num[s[3][i]-'A'+1];
//if(c1==-1 || c2==-1 || c3==-1) continue;
//if((c1+c2)%n!=c3 && (c1+c2+1)%n!=c3) return;
}
if(num[s[y][x]-'A'+1]==-1){//当前这一位置未填
for(int i=n-1;i>=0;i--){
if(!vis[i]){
if(y != 3){//不是结果,可以试填
num[s[y][x]-'A'+1]=i;
vis[i]=1;
dfs(x,y+1,w);
vis[i]=0;
num[s[y][x]-'A'+1]=-1;
}
else{
c=num[s[1][x]-'A'+1]+num[s[2][x]-'A'+1] + w;
//if(c%n!=i) continue;
vis[i]=1;
num[s[3][x]-'A'+1]=i;
dfs(x-1,1,c/n);//进入下一位
vis[i]=0;
num[s[3][x]-'A'+1]=-1;
}
}
}
}
else{
if(y!=3) dfs(x,y+1,w);
else{
c=num[s[1][x]-'A'+1] + num[s[2][x]-'A'+1]+w;
//if(c%n!=num[s[3][x]-'A'+ 1]) return;
dfs(x-1,1,c/n);
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=3;i++) scanf("%s",s[i]+1);
memset(num,-1,sizeof(num));
dfs(n,1,0);
return 0;
}