nyoj 491 幸运三角形

本文探讨了一种计算幸运三角形个数的方法,并通过优化剪枝策略来提高效率。详细介绍了从第一行符号开始搜索,利用二维矩阵存储并递推生成后续行的符号,同时运用剪枝技术减少不必要的搜索,最终实现对幸运三角形数量的高效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=491


////////////////////////////////////////////

此题最简单的算法就是打表,刚开始做的时候直接搜索,减了总数为奇数的情况,但还是TLE

无奈上网搜了下,但大部分都是打表,找了几个没有打表的,把代码粘上仍然是TLE

无奈看了看书,于是又想了想,看了下书,结果看到书上有个这样的题

其思路如下:

对第一行的n个节点分别赋值0 1进行搜索,这个大部分都这样;

用一个二维矩阵p存三角形中每个点的值,当搜索到第i个点的时候,对第1行第i个赋值,然后退出第2行第i-1个,由此推出第3行第i-2个;把结果存到p中;搜索每个点的时候都要记录’+‘出现的次数,记为count;

剪枝主要是当搜索到第i个点的时候 ,如果count>n*(n-1)/4  或者是 i*(i-1)/2-count>n*(n-1)/4  即'+'的个数 或 ‘-’的个数大于三角形中总点数的一半,就退出;如果没有此剪枝,应该不好过;

代码如下:

#include <iostream>
using namespace std;
class Triangle
{
	friend int compute(int);
private:
	void Backtrack(int t);
	int n,     //第一行的符号个数
		half,  //n*(n+1)/4
		count, //当前‘+’个数
		**p;  //幸运三角形矩阵
	long sum; //已找到的幸运三角形个数
};
void Triangle::Backtrack(int t)
{
	if((count>half)||(t*(t-1)/2-count>half))//当搜索到此层时,如果'+'或’-‘有大于总符号的一半,就退出;
		return ;
	int i,j;
	if(t>n)
		sum++;
	else
		for(i=0;i<2;i++)
		{
			p[1][t]=i;
			count+=i;
			for(j=2;j<=t;j++)
			{
				p[j][t-j+1]=p[j-1][t-j+1]^p[j-1][t-j+2]; //由p[1][t]的值退出t左斜下方的符号;
				count+=p[j][t-j+1]; //如果为1 则count++;
			}
			Backtrack(t+1);
			for(j=2;j<=t;j++)
				count-=p[j][t-j+1];
			count-=i;
		}
}
int compute(int n)//计算节点为n的幸运三角形的个数;
{
	Triangle x;
	x.n=n;
	x.count=0;
	x.half=n*(n+1)/2;
	x.sum=0;
	if(x.half%2==1)//如果三角形中总符号数为奇数,则返回0;
		return 0;
	x.half=x.half/2;
	int i,j;
	int **p=new int *[n+1];
	for(i=0;i<=n;i++)
		p[i]=new int [n+1];
	for(i=0;i<=n;i++)
		for(j=0;j<=n;j++)
			p[i][j]=0;
	x.p=p;
	x.Backtrack(1);
	return x.sum;
}
int main()
{
	int n;
	while(cin>>n)
	{
		int res=compute(n);
		cout<<res<<endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值