[洛谷]P1537 弹珠 (#搜索)

84 篇文章 1 订阅
75 篇文章 0 订阅

题目描述

玛莎和比尔各自有自己的弹珠收藏。他们想重新分配收藏品,使两人能平等拥有弹珠。如果所有的弹珠的价值相同,那么他们就可以平分。但不幸的是,有一些弹珠更大,或者更美丽,所以,玛莎和比尔给每个弹珠一个1到6的价值。现在他们想平分这些弹珠,使每个人得到的总价值相同。不幸的是,他们发现,他们可能无法以这种方式分弹珠(即使弹珠的总价值为偶数)。例如,如果有一个价值为1、一个价值为3和两个价值为4的弹珠,这样他们就不能把弹珠分为价值相等的两部分。因此,他们想要你写一个程序,告诉他们是否能将所有弹珠分成价值相等的两部分。

输入输出格式

输入格式:

输入文件有若干行,行中包含六个非负整数N1,。..,N6,其中mi是数值i的弹珠的价值。最大弹珠总数将达到20000。

输入文件的最后一行是0 0 0 0 0 0 。不要处理这一行。

输出格式:

对于每一组数据,输出"Collection #k:", k为输出的是第几组, 接着是"Can be divided." 或 "Can't be divided.".

每一组输出后多打一个空行。

输入输出样例

输入样例#1

1 0 1 2 0 0 
1 0 0 0 1 1 
0 0 0 0 0 0 

输出样例#1

Collection #1:
Can't be divided.

Collection #2:
Can be divided.

思路

正解应该是背包,但是我不会写。。你们动态规划那么难的么?

因为正解是背包,所以标签会打上背包dp。

dfs:

暴力枚举每个弹珠,看看是否能凑成两个弹珠总价值的一半。(一开始我写的暴力6重循环,后来一直20分)

#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
int n,s,a[7],flag;
void dfs(int now,int v)//now是当前的总价值,cnt是已经凑够几个弹珠总价值的一般 
{
	if(now==s)//如果当前总价值是所有弹珠价值一半 
	{
		v++;//凑够弹珠+1 
		now=0;//总价值=0 
		if(v==2)//如果已经找到了2个弹珠总价值的一半 
		{
			flag=1;//标记 
			return;
		}
	}
	register int i;
	for(i=6;i>=1;i--)//不知道为什么倒着搞就能很快 
	{
		if(a[i] && now+i<=s)//如果还有价值为i的弹珠并且当前总价值加上这个弹珠的价值不超过所有弹珠总价值的一半 
		{
			a[i]--;
			dfs(now+i,v);
			if(flag)//如果找到解 
			{
				return;
			}
			a[i]++;
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	register int i,j,k(1);
	while(cin>>a[1]>>a[2]>>a[3]>>a[4]>>a[5]>>a[6])
	{
		flag=0,s=0;
		for(i=1;i<=6;i++)
		{
			s+=a[i]*i;//总价值 
		}
		if(s==0)
		{
			return 0;
		}
		cout<<"Collection #"<<k<<":"<<endl;
		if(s%2==1)//如果是奇数必然无解 
		{
			goto lp;
		}
		s>>=1;//总价值一半 
		dfs(0,0);
		if(flag==1)
		{
			cout<<"Can be divided."<<endl<<endl;
			k++;
			continue;
		}
		else
		{
			goto lp;
		}
		lp:
			cout<<"Can't be divided."<<endl;
			k++;
			cout<<endl;
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值