ybtoj DFS 1 拔河比赛 数独游戏 虫食算

前情详见 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。其中注释掉的代码均为剪枝.......整体流程大概是依次枚举哪个字母对应哪个数字,从右往左一列一列扫,别忘了进位。期间分两钟情况:

  1. 右侧所有字母均已确定,可知进位是多少
  2. 有字母未知,进位为一或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;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

xiyuping24

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

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

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

打赏作者

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

抵扣说明:

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

余额充值