2024/2/1

P1616 疯狂的采药

题目描述

LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是 LiYuxiang,你能完成这个任务吗?

此题和原题的不同点:

11. 每种草药可以无限制地疯狂采摘。

22. 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!

输入格式

输入第一行有两个整数,分别代表总共能够用来采药的时间 t 和代表山洞里的草药的数目 m。

第 2 到第 (m+1) 行,每行两个整数,第 (i+1) 行的整数 ai​,bi​ 分别表示采摘第 i 种草药的时间和该草药的价值。

输出格式

输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

由于每种药材可以无限次采集,所以这是一道完全背包的题目

完全背包可以使用1维数组来构建状态转移方程

此时背包的遍历是从w[i]开始

因为dp[j]=max(dp[j],dp[j-w[i]]+v[i])

由于一开始j=w[i],所以dp[j]会被初始化为dp[j-w[i]]+v[i],所以一个数据会被多次加入

dp[1] = dp[1-w[0]] + v[0]

dp[2] = dp[2-w[0]] + v[0]

达成了药材可以无限采集的条件

完整代码

#include<bits/stdc++.h>
using namespace std;
long long t,m;
long long w[10005],v[10005];
long long dp[10000005];
int main()
{
	cin>>t>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>w[i]>>v[i];
	}
	for(int i=1;i<=m;i++)
    {
    	for(int j=w[i];j<=t;j++)
    	{
    		dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
		}
	}
	cout<<dp[t];
	return 0;
}

P3367 【模板】并查集

题目描述

如题,现在有一个并查集,你需要完成合并和查询操作。

输入格式

第一行包含两个整数 N,M ,表示共有N 个元素和 M 个操作。

接下来 M 行,每行包含三个整数 Zi​,Xi​,Yi​ 。

当 Zi​=1 时,将 Xi​ 与 Yi​ 所在的集合合并。

当 Zi​=2 时,输出 Xi​ 与 Yi​ 是否在同一集合内,是的输出 Y ;否则输出 N 。

输出格式

对于每一个Zi​=2 的操作,都有一行输出,每行包含一个大写字母,为 Y 或者 N 。

这道是并查集的模板题,要写这道题就要学习并查集的算法

并查集是一种树状的数据结构,用于解决不相交集合的合并和查询问题

主要操作有三个

  1. 初始化:将每个点所在集合初始化为它本身
  2. 查找,查找元素所在的集合
  3. 合并:按所需把对应两个元素所在集合合并一起

初始化函数

void iint()
{
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
	}
}

查找函数

int find(int u)
{
	if(fa[u]==u)
	{
		return u;
	}
	else
	{
		return fa[u]=find(fa[u]);
	}
}

合并函数

关于合并函数,还需要在合并前判断其是否都在同一个集合里

如果两个元素都在同一个集合里

有f[a]==f[b]

void join(int u,int v)
{
	u=find(u);
	v=find(v);
	if(v==u) return;
     fa[v]=u;
}
bool judge(int u,int v)
{
	u=find(u);
	v=find(v);
	return u==v;
}

完整代码

#include<bits/stdc++.h>
using namespace std;
int n;
int fa[10005];
void iint()
{
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
	}
}
int find(int u)
{
	if(fa[u]==u)
	{
		return u;
	}
	else
	{
		return fa[u]=find(fa[u]);
	}
}
void join(int u,int v)
{
	u=find(u);
	v=find(v);
	if(v==u) return;
     fa[v]=u;
}
bool judge(int u,int v)
{
	u=find(u);
	v=find(v);
	return u==v;
}

int main()
{
	int m,z,x,y;
	cin>>n>>m;
	iint();
	for(int i=1;i<=m;i++)
	{
		cin>>z>>x>>y;
		if(z==1)
		{
			join(x,y);
		}
		if(z==2)
		{
			if(judge(x,y))
			{
				cout<<"Y"<<endl;
			}
			else
			{
				cout<<"N"<<endl;
			}
		}
	}
	return 0;
}

Spreadsheets

题意翻译

人们常用的电子表格软件(比如: Excel)采用如下所述的坐标系统:

第一列被标为 A,第二列为 B,以此类推,第 2626 列为 Z。接下来为由两个字母构成的列号: 第 2727 列为 AA,第 2828 列为 AB ⋯⋯ 在标为 ZZ 的列之后则由三个字母构成列号,如此类推。

行号为从 11 开始的整数。

单元格的坐标由列号和行号连接而成。比如,BC23 表示位于第 5555 列 2323 行的单元格。

有时也会采用被称为 RXCY 的坐标系统,其中 X 与 Y 为整数,坐标 (X,Y) 直接描述了对应单元格的位置。比如,R23C55 即为前面所述的单元格。

您的任务是编写一个程序,将所给的单元格坐标转换为另一种坐标系统下面的形式。

输入

第一行一个整数 n (1≤n≤10^5) 表示将会输入的坐标的数量。

接下来 n 行,每行一个坐标。

注意: 每个坐标都是正确的。此外不会出现行号或列号大于 106106 的单元格。

输出 n 行,每行一个被转换的坐标。

输出

n 行,每行一个被转换的坐标。

从1对应A到26对应Z

可以把它看作一个26进制

因此我们要做的是解决26进制和10进制之间的转换

用数余26得的数对应26个字母

对于大于26的字符

这里用一个while循环来处理

每次除26来获得后一位的字符转换

但是当余数为0时对应的是Z,要特判

完整代码

#include<bits/stdc++.h>
using namespace std;
int n,lg;
string s;
void transform(bool mode)//参数为判断函数
{
	char tr[]=" ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	int lh=0,hh=0;//列号和行号
	if(mode)//第一种形式RXCY转EXcel
	{
		int r=s.find("R");
		int c=s.find("C");
		for(int i=r+1;i<c;i++)
		{
			hh=hh*10+s[i]-'0';//行不需要转换
		}
		for(int i=c+1;i<lg;i++)
		{
			lh=lh*10+s[i]-'0';//把列转成数字好转换
		}
		string ans;//定义字符串
		while(lh>0)
		{
			int temp=lh%26;
			if(temp==0)//特判余数为0,此时为Z
			{
				temp=26;
				lh-=26;
			}
			ans+=tr[temp];//用temp余数去对应字母,将转换字符加入字符串
				lh/=26;//获得后一位进行转换
		}
		reverse(ans.begin(),ans.end());//因为ans加入字符是反着加入,从低到高,因此需要反转
		cout<<ans<<hh<<endl;//输出
	}
	else//EXCel转RXCY
	{
	  for(int i=0;i<lg;i++)
	  {
	  	if(isdigit(s[i]))//读到数字
	  	{
	  		hh=hh*10+s[i]-'0';//行不用转换
		}
		else
		{
			lh=lh*26+s[i]-'A'+1;//将列转换
		}
	  }
	  cout<<"R"<<hh<<"C"<<lh<<endl;
	}
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>s;
		bool mode=0,flag=0;
		lg=s.length();
		for(int i=0;i<lg;i++)
		{
			if(isdigit(s[i]))//读到数字
			{
				flag=1;
			}
			if(flag&&s[i]=='C')//EXcel的C前面不含数字,RXCY的C前面必含数字
			{
				mode=1;
				break;
			}
		}
		transform(mode);
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值