CSP第32次仓库规划、因子化简、树上搜索C++代码

第一题仓库规划

西西艾弗岛上共有 n 个仓库,依次编号为 1⋯n。每个仓库均有一个 m 维向量的位置编码,用来表示仓库间的物流运转关系。

具体来说,每个仓库 i 均可能有一个上级仓库 j,满足:仓库 j 位置编码的每一维均大于仓库i 位置编码的对应元素。比如编码为 (1,1,1) 的仓库可以成为 (0,0,0) 的上级,但不能成为 (0,1,0) 的上级。如果有多个仓库均满足该要求,则选取其中编号最小的仓库作为仓库 i 的上级仓库;如果没有仓库满足条件,则说明仓库 i 是一个物流中心,没有上级仓库。

现给定 n 个仓库的位置编码,试计算每个仓库的上级仓库编号。

一个简单的模拟题

#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
int ma[1001][11];
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		cin>>ma[i][j];
		
	}
	for(int i=1;i<=n;i++)
	{
		bool pd2=false;
		for(int j=1;j<=n;j++)
		{
			bool pd=true;
			if(i==j) continue;
			for(int k=1;k<=m;k++)
			{
				if(ma[j][k]>ma[i][k])
				{
					continue;
				}
				else 
				{
					pd=false;
					break;
				}
			}
			if(pd)
			{
				pd2=true;
				cout<<j<<endl;
				break;
			}
			
		
		}
		if(!pd2)
		{
			cout<<0<<endl;
		}
		
	}
	return 0;
 } 

第二题因子化简

小 P 同学在学习了素数的概念后得知,任意的正整数 n都可以唯一地表示为若干素因子相乘的形式。如果正整数 n 有 m 个不同的素数因子 p_1,p_2,p_3,...,则可以表示为:n=p_1^{t1}*p_2^{t2}*...*p_m^{tn}

小 P 认为,每个素因子对应的指数 t_i 反映了该素因子对于 n 的重要程度。现设定一个阈值 k,如果某个素因子 t_i 对应的指数  t_i 小于 k,则认为该素因子不重要,可以将 p_i^{ti} 项从 n 中除去;反之则将  p_i^{ti} 项保留。最终剩余项的乘积就是 n 简化后的值,如果没有剩余项则认为简化后的值等于 1。

试编写程序处理 q 个查询:

  • 每个查询包含两个正整数 n 和 k,要求计算按上述方法将 n 简化后的值。

利用线性筛筛出所有素数后,一个一个遍历去尝试,即可得到答案

#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
bool numlist[100000001];
int prime[2000001], tot;
void work(int n){
	for(int i=2; i*i<=n; i++){
		if(numlist[i]==false){
			prime[++tot] = i ;
			for(int j=i; i*j<=n; j++)
				numlist[i*j] = true;
		}
	}
	return;
}
int main()
{
	int q,t2;
	long long t1;
	work(1000001);
	cin>>q;
	for(int i=1;i<=q;i++)
	{
		
		cin>>t1>>t2;
		long long ans=1,temp=0,jl=1;
		for(int t=1;t<=tot;t++)
		{
			temp=0,jl=1;
			while(t1%prime[t]==0)
			{
				t1=t1/prime[t];
				jl=jl*prime[t];
				temp++;
			}
			if(temp>=t2)
			ans=ans*jl;
		}
		cout<<ans<<endl;
	}
	return 0;
 } 

第三题树上搜索

西西艾弗岛大数据中心为了收集用于模型训练的数据,推出了一项自愿数据贡献的系统。岛上的居民可以登录该系统,回答系统提出的问题,从而为大数据中心提供数据。为了保证数据的质量,系统会评估回答的正确性,如果回答正确,系统会给予一定的奖励。

近期,大数据中心需要收集一批关于名词分类的数据。系统中会预先设置若干个名词类别,这些名词类别存在一定的层次关系。例如,“动物”是“生物”的次级类别,“鱼类”是“动物”的次级类别,“鸟类”是“动物”的次级类别,“鱼类”和“鸟类”是“动物”下的邻居类别。这些名词类别可以被按树形组织起来,即除了根类别外,每个类别都有且仅有一个上级类别。
并且所有的名词都可以被归类到某个类别中,即每个名词都有且仅有一个类别与其对应。一个类别的后代类别的定义是:若该类别没有次级类别,则该类别没有后代类别;否则该类别的后代类别为该类别的所有次级类别,以及其所有次级类别的后代类别。

下图示意性地说明了标有星号的类别的次级类别和后代类别。

次级类别与后代类别

系统向用户提出问题的形式是:某名词是否属于某类别,而用户可以选择“是”或“否”来回答问题。该问题的含义是:某名词是否可以被归类到某类别或其后代类别中。

例如,要确定名词“鳕鱼”的类别,系统会向用户提出“鳕鱼是否属于动物”,当用户选择“是”时,系统会进一步询问“鳕鱼是否属于鱼类”,当用户选择“是”时,即可确定“鳕鱼”可以被归类到“鱼类”这一类别。

此外,如果没有更具体的分类,某一名词也可以被归类到非叶子结点的类别中。例如,要确定“猫”的类别,系统可以向用户提出“猫是否属于动物”,当用户选择“是”时,系统会进一步分别询问“猫”是否属于“鱼类”和“鸟类”,当两个问题收到了否定的答案后,系统会确定“猫”的类别是“动物”。

大数据中心根据此前的经验,已经知道了一个名词属于各个类别的可能性大小。为了用尽量少的问题确定某一名词的类别,大数据中心希望小 C 来设计一个方法,以减少系统向用户提出的问题的数量。

问题描述

小 C 观察了事先收集到的数据,并加以统计,得到了一个名词属于各个类别的可能性大小的信息。具体而言,每个类别都可以赋予一个被称为权重的值,值越大,说明一个名词属于该类别的可能性越大。由于每次向用户的询问可以获得两种回答,小 C 联想到了二分策略。他设计的策略如下:

  1. 对于每一个类别,统计它和其全部后代类别的权重之和,同时统计其余全部类别的权重之和,并求二者差值的绝对值,计为 w_\beta
  2. 选择 w_\beta 最小的类别,如果有多个,则选取编号最小的那一个,向用户询问名词是否属于该类别;
  3. 如果用户回答“是”,则仅保留该类别及其后代类别,否则仅保留其余类别;
  4. 重复步骤 1,直到只剩下一个类别,此时即可确定名词的类别。

小 C 请你帮忙编写一个程序,来测试这个策略的有效性。你的程序首先读取到所有的类别及其上级次级关系,以及每个类别的权重。你的程序需要测试对于被归类到给定类别的名词,按照上述策略提问,向用户提出的所有问题。

一个大模拟题,对于单个查询,遍历所有存活的节点,遍历出最小的节点,选择其子树,如果目标节点在子树里面则只保留这颗子树,否则,去除这颗子树,更新信息。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cmath>
using namespace std;
int n,m;
long long stototval,val[2001],sonval[2001],totval,stosonval[2001];
bool live[2001],livefind[2001];
long long  lives,stolives;
int head[2001],tot=1;
struct node
{
	int to,next;
}ma[10000001];
void add(int a,int b)
{
	ma[tot].to=b;
	ma[tot].next=head[a];
	head[a]=tot++;
}
long long  firstdfs(int now)
{
	long long sum=0;
	stolives++;
	for(int i=head[now];i;i=ma[i].next)
	{
		int y=ma[i].to;
		sum+=firstdfs(y);
	}
	sonval[now]=sum+val[now];
	return sonval[now];
}
bool find(int now,int mb)
{ 
	bool sum=0;
	if(now==mb) return 1;
	for(int i=head[now];i;i=ma[i].next)
	{
		int y=ma[i].to;
		if(live[y])
		sum+=find(y,mb);
	}

	return sum;
}
long long dfsup(int now)
{
	long long temp=0;
	livefind[now]=true;
	
	for(int i=head[now];i;i=ma[i].next)
	{int y=ma[i].to;
			
		
		if(live[y])
		temp+=dfsup(y);
	}
	temp+=val[now];
	sonval[now]=temp;
	return temp;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>val[i];
	}
	for(int i=2;i<=n;i++)
	{
		int fa;
		cin>>fa;
		add(fa,i);
	}
	firstdfs(1);
	for(int i=1;i<=n;i++)
		stosonval[i]=sonval[i];
	stototval=sonval[1];
	for(int opt=1;opt<=m;opt++)
	{
		
		int t1;
		cin>>t1;
		lives=stolives;
		int root=1;
		root=1;
		totval=stototval;
		for(int i=1;i<=n;i++)
		{	
			sonval[i]=stosonval[i];
			live[i]=true;
			livefind[i]=false;
		}
		while(lives>=2)
		{
			totval=0;
			for(int i=1;i<=n;i++)
			if(live[i])
			totval+=val[i];
		long long maxn=9999999999999,mb=-1;
		for(int i=1;i<=n;i++)
		{
			if(live[i])
			if(abs(2*sonval[i]-totval)<maxn)
			{
				maxn=abs(2*sonval[i]-totval);
				mb=i;
			}
		}
		cout<<mb<<" ";
		if(find(mb,t1))
		{
			lives=0;
			root=mb;
			dfsup(mb);
			for(int i=1;i<=n;i++)
			{
				if(livefind[i])
				{
					live[i]=true;
					lives++;
				}
				else 
				{
					live[i]=false;
				}
				livefind[i]=false;
				
			}
		}
		else
		{
			live[mb]=false;
			lives=0;
			dfsup(root);
			for(int i=1;i<=n;i++)
			{
				if(livefind[i])
				{
					live[i]=true;lives++;
				}
				else 
				{
					live[i]=false;
				}
				livefind[i]=false;
				
			}
		}
	}
	cout<<endl;
	}
	return 0;
 } 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值