8.22训练17 回溯剪枝

Tempter of the Bone

Cake


今天又出去玩了,没完成,,


Tempter of the Bone

题目大意、剪枝思想看上一篇文章
这个题错的原因是:
1.没想明白总时间和剩余时间的区别
2.continue达成break
我是傻逼


Cake

Problem Description
There are m soda and today is their birthday. The 1-st soda has prepared n cakes with size 1,2,…,n. Now 1-st soda wants to divide the cakes into m parts so that the total size of each part is equal.

Note that you cannot divide a whole cake into small pieces that is each cake must be complete in the m parts. Each cake must belong to exact one of m parts.
Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first contains two integers n and m (1≤n≤105,2≤m≤10), the number of cakes and the number of soda.
It is guaranteed that the total number of soda in the input doesn’t exceed 1000000. The number of test cases in the input doesn’t exceed 1000.
Output
For each test case, output “YES” (without the quotes) if it is possible, otherwise output “NO” in the first line.

If it is possible, then output m lines denoting the m parts. The first number si of i-th line is the number of cakes in i-th part. Then si numbers follow denoting the size of cakes in i-th part. If there are multiple solutions, print any of them.
Sample Input
4
1 2
5 3
5 2
9 3
Sample Output
NO
YES
1 5
2 1 4
2 2 3
NO
YES
3 1 5 9
3 2 6 7
3 3 4 8
题目大意这个就是把1、2、3……n分成m组,使得每组总和相等。
这个题选取顺序就很重要了。要优先选取大的。
记得昨天的题吗?(还是前天)我问题出错在这一组先选取这个可能导致另一组无法凑齐,今天相出了解决方法。就是先选取大的,因为造成上述后果的原因无非是能拿一个整块的,却拿了几个小的。
比如我还差5,这时我可以拿5,可以拿1和4.如果我拿了1和4就可能导致后面的无法凑齐。如果我优先选取大的就没这些顾虑了。直接m-1次选取即可 。
做这个题的时候爆栈了。解决方法一就是上述,循环m-1次。另外一个方法就是用老师的代码方法,用一个循环选取当前数字之后的数字。这时如果不选取就不会有一个栈了。应该能减少不小的空间。
代码如下

//You has the final say in what kind of life you want.
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#define MAX 100000+10
using namespace std;
int n,m;
bool vis[MAX];
vector<int>ans[20];
bool devide(int x,int s,int cur,int now)
{
	if(now==x)
	{
//		for(int i=1;i<=n;i++)
//			if(!vis[i])
//				ans[s].push_back(i);
		return 1;
	}
	if(cur<=0)return 0;
	

	if(!vis[cur]&&now+cur<=x)
	{
		vis[cur]=1;
		if(devide(x,s,cur-1,now+cur))
		{
			ans[s].push_back(cur);
			return 1;
		}
		vis[cur]=0;
	}
	
	long long temp=(long long)(cur)*(cur-1)/2;
	if(now+temp>=x)
		if(devide(x,s,cur-1,now))
			return 1;
	return 0;
}

bool check(int x)
{
	for(int i=0;i<m;i++)
	{
		if(!devide(x,i,n,0))
			return 0;
	}
	for(int i=1;i<=n;i++)
		if(!vis[i])
			ans[3].push_back(i);
	return 1;	
}

int main()
{
	int T;
	long long temp;
	cin>>T;
	while(T--)
	{
		for(int i=0;i<20;i++)
			ans[i].clear();
		memset(vis,0,sizeof(vis));
		scanf("%d%d",&n,&m);
		temp=(long long)(1+n)*n/2;
		if(temp%m||temp/m<n)
		{
			printf("NO\n");
			continue;
		}
		if(check(temp/m))
		{
			printf("YES\n");
			for(int i=0;i<m;i++)
			{
				printf("%d ",ans[i].size());
			//	for(int j=ans[i].size()-1;j>=0;j--)
				for(int j=0;j<ans[i].size();j++)
					printf("%d ",ans[i][j]);
				printf("\n");
			}
		}
		else printf("NO\n");
	}
	return 0;
}


最近快结束了,很浮躁。还有很长的路要走,别松懈啊。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值