巩固练习!

文章提供了多个问题的解决方案,包括从低等级星球到高等级星球的最低费用航线寻找、跑步圈数的递增策略、使用砝码称重的不同组合计算以及如何确定遗址位置的最大正方形面积。此外,还介绍了一个环境治理问题,涉及城市间道路灰尘度的优化策略和指标计算。
摘要由CSDN通过智能技术生成

T1:汤姆斯的天堂梦

汤姆斯生活在一个等级为 00 的星球上。那里的环境极其恶劣,每天 1212 小时的工作和成堆的垃圾让人忍无可忍。他向往着等级为 NN 的星球上天堂般的生活。

有一些航班将人从低等级的星球送上高一级的星球,有时需要向驾驶员支付一定金额的费用,有时却又可以得到一定的金钱。

汤姆斯预先知道了从 00 等级星球去 NN 等级星球所有的航线和需要支付(或者可以得到)的金钱,他想寻找一条价格最低(甚至获得金钱最多)的航线。

输入格式

第一行一个正整数 NN(N \le 100N≤100),接下来的数据可分为 NN 个段落,每段的第一行一个整数 K_iKi​(K_i \le 100Ki​≤100),表示等级为 ii 的星球有 K_iKi​ 个。

接下来的 K_iKi​ 行中第 jj 行依次表示与等级为 ii,编号为 jj 的星球相连的等级为 i - 1i−1 的星球的编号和此航线需要的费用(正数表示支出,负数表示收益,费用的绝对值不超过 10001000)。

每行以 00 结束,每行的航线数 \le 100≤100。

输出格式

输出所需(或所得)费用。正数表示支出,负数表示收益。

输入输出样例

输入 #1复制

3
2
1 15 0
1 5 0
3
1 -5 2 10 0
1 3 0
2 40 0
2
1 1 2 5 3 -5 0
2 -19 3 -20 0

输出 #1复制

-1

思路:

对于每一条航线有一个状态转移f[i][j]=min(f[i][j],f[i-1][x]+w),其中f[i][j]代表到i级j号星球的最小花费。然后处理一下输入,输出f[n][j]中的最小值即可。

#include<bits/stdc++.h>
using namespace std;
int n,f[1005][1005];//f[i][j]代表到i级j星球所需的最小代价
int ans=0x3f3f3f,t,x,w;;
int main()
{
	cin>>n;
	
	for(int i=1;i<=n;i++){
		
		cin>>t;
		for(int j=1;j<=t;j++){
			f[i][j]=0x3f3f;
			cin>>x;
			while(x!=0)//处理输入
			{
				cin>>w;
				f[i][j]=min(f[i][j],f[i-1][x]+w);
				cin>>x;
			}
		}
	}
	for(int i=1;i<=t;i++)ans=min(ans,f[n][i]);//输出最小答案(花费)
	cout<<ans<<endl;
 	return 0;
}

T2:跑步

路人甲准备跑 nn 圈来锻炼自己的身体,他准备分多次(\gt1>1)跑完,每次都跑正整数圈,然后休息下再继续跑。

为了有效地提高自己的体能,他决定每次跑的圈数都必须比上次跑的多。

可以假设他刚开始跑了 00 圈,那么请问他可以有多少种跑完这 nn 圈的方案?

输入格式

一行一个整数,代表 nn。

输出格式

一个整数表示跑完这 nn 圈的方案数。

输入输出样例

输入 #1复制

212

输出 #1复制

995645335

思路:

将这个问题看作一个01背包问题,最终的总圈数n就是背包容量,每跑j圈(这个j在逐渐增大),对应背包容量减少j,题目所求即是01背包的方案数。

#include<bits/stdc++.h>
using namespace std;
int n;
long long f[505];

int main()
{
	cin>>n;
	f[0]=1;//借一个1 
	for(int i=1;i<=n;i++){//01背包求方案数
		for(int j=n;j>=i;j--){
			f[j]+=f[j-i];//
		}
	}
	cout<<f[n]-1<<endl;
 	return 0;
}

T3:砝码称重

你有一架天平和 NN 个砝码, 这 NN 个砝码重量依次是 W_{1}, W_{2}, \cdots, W_{N}W1​,W2​,⋯,WN​ 。 请你计算一共可以称出多少种不同的重量?

注意砝码可以放在天平两边。

输入格式

输入的第一行包含一个整数 NN 。

第二行包含 NN 个整数: W_{1}, W_{2}, W_{3}, \cdots, W_{N}W1​,W2​,W3​,⋯,WN​ 。

输出格式

输出一个整数代表答案。

输入输出样例

输入 #1复制

3
1 4 6

输出 #1复制

10

思路:

f[i][j]代表用i个砝码能否称出重量为j的质量,首先一点可以知道:把所有砝码全部累加起来这个重量sum是肯定能够称出来的,然后逐步将这个重量递减,然后会产生四种情况:

  1. 本身这个重量j在砝码中就存在
  2. 砝码不变也能称出该重量
  3. 减去一个砝码也能称出该重量
  4. 加上一个砝码也能称出该重量
#include<bits/stdc++.h>
using namespace std;
int n,sum,w[105],ans;
int f[105][100005];

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>w[i];
		sum+=w[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=sum;j>=0;j--){
			if(j==w[i])f[i][j]=1;
			else if(f[i-1][j]==1)f[i][j]=1;
			else if(f[i-1][abs(j-w[i])])f[i][j]=1;
			else if(f[i-1][j+w[i]])f[i][j]=1;
			
		}
	}
	/*for(int i=1;i<=n;i++){
		for(int j=1;j<=sum;j++){
			if(f[i][j])cout<<"the fama cnt is "<<i<<" the weight is "<<j<<endl;
		}
	}*/
	for(int i=1;i<=sum;i++){
		if(f[n][i])ans++;
	}
	cout<<ans<<endl;
 	return 0;
}

T4:遗址

很久很久以前有一座寺庙,从上往下看寺庙的形状正好是一个正方形,由 44 个角上竖立的圆柱搭建而成。现在圆柱都倒塌了,只在地上留下圆形的痕迹,可是现在地上有很多这样的痕迹,专家说一定是最大的那个。

写一个程序,给出圆柱的坐标,找出由 44 个圆柱构成的最大的正方形,因为这就是寺庙的位置,要求计算出最大的面积。注意正方形的边不一定平行于坐标轴。

例如图有 1010 根柱子,其中 (4,2),(5,2),(5,3),(4,3)(4,2),(5,2),(5,3),(4,3) 可以形成一个正方形,(1,1),(4,0),(5,3),(2,4)(1,1),(4,0),(5,3),(2,4) 也可以,后者是其中最大的,面积为 1010。

输入格式

第一行包含一个 N(1\leq N\leq 3000)N(1≤N≤3000),表示柱子的数量。

接下来 NN 行,每行有两个空格隔开的整数表示柱子的坐标(坐标值在 00 到 50005000 之间),柱子的位置互不相同。

输出格式

如果存在正方形,输出最大的面积,否则输出 00。

输入输出样例

输入 #1复制

 10
 9 4
 4 3
 1 1
 4 2
 2 4
 5 8
 4 0
 5 3
 0 5
 5 2

输出 #1复制

10

思路:

首先最简单的就是枚举四个顶点,然后判断这个四个顶点能否构成一个正方形,然后再计算他们的面积最大值。

其次就是下面作法:

 

#include<bits/stdc++.h>
using namespace std;
int n;
struct dot{
	int x,y,z;
}d[3005];
bool f[5005][5005];
int ans=-1;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>d[i].x>>d[i].y;
		f[d[i].x][d[i].y]=1;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			int dx=fabs(d[i].x-d[j].x),dy=fabs(d[i].y-d[j].y);
			int ni_x=d[i].x+dy,ni_y=d[i].y-dx;
			int nj_x=d[j].x+dy,nj_y=d[j].y-dx;
			if(ni_x>5000||ni_y>5000||ni_x<0||ni_y<0||nj_x>5000||nj_x<0||nj_y>5000||nj_y<0)continue;
			if(f[ni_x][ni_y]&&f[nj_x][nj_y]){
				int s=dx*dx+dy*dy;//总面积等于x坐标之差的平方与y坐标之差的平方
				ans=max(s,ans);
			}
		}
	}
	if(ans==-1)cout<<0<<endl;
	else cout<<ans<<endl;
 	return 0;
}

T5:环境治理

LQ 国拥有 nn 个城市,从 00 到 n - 1n−1 编号,这 nn 个城市两两之间都有且仅有一条双向道路连接,这意味着任意两个城市之间都是可达的。每条道路都有一个属性 DD,表示这条道路的灰尘度。当从一个城市 A 前往另一个城市 B 时,可能存在多条路线,每条路线的灰尘度定义为这条路线所经过的所有道路的灰尘度之和,LQ 国的人都很讨厌灰尘,所以他们总会优先选择灰尘度最小的路线。

LQ 国很看重居民的出行环境,他们用一个指标 PP 来衡量 LQ 国的出行环境,PP 定义为:

P=\sum \limits_{i=0}^{n-1} \sum \limits_{j=0}^{n-1} d(i,j)P=i=0∑n−1​j=0∑n−1​d(i,j)

其中 d(i,j)d(i,j) 表示城市 ii 到城市 jj 之间灰尘度最小的路线对应的灰尘度的值。

为了改善出行环境,每个城市都要有所作为,当某个城市进行道路改善时,会将与这个城市直接相连的所有道路的灰尘度都减少 11,但每条道路都有一个灰尘度的下限值 LL,当灰尘度达到道路的下限值时,无论再怎么改善,道路的灰尘度也不会再减小了。

具体的计划是这样的:

  • 第 11 天,00 号城市对与其直接相连的道路环境进行改善;
  • 第 22 天,11 号城市对与其直接相连的道路环境进行改善;

……

  • 第 nn 天,n - 1n−1 号城市对与其直接相连的道路环境进行改善;
  • 第 n + 1n+1 天,00 号城市对与其直接相连的道路环境进行改善;
  • 第 n + 2n+2 天,11 号城市对与其直接相连的道路环境进行改善;

……

LQ 国想要使得 PP 指标满足 P \leq QP≤Q。请问最少要经过多少天之后,PP 指标可以满足 P \leq QP≤Q。如果在初始时就已经满足条件,则输出 00;如果永远不可能满足,则输出 -1−1。

输入格式

输入的第一行包含两个整数 n, Qn,Q,用一个空格分隔,分别表示城市个数和期望达到的 PP 指标。

接下来 nn 行,每行包含 nn 个整数,相邻两个整数之间用一个空格分隔,其中第 ii 行第 jj 列的值 D_{i,j} (D_{i,j}=D_{j,i},D_{i,i} = 0)Di,j​(Di,j​=Dj,i​,Di,i​=0) 表示城市 ii 与城市 jj 之间直接相连的那条道路的灰尘度。

接下来 nn 行,每行包含 nn 个整数,相邻两个整数之间用一个空格分隔,其中第 ii 行第 jj 列的值 L_{i,j} (L_{i,j} = L_{j,i}, L_{i,i} = 0)Li,j​(Li,j​=Lj,i​,Li,i​=0) 表示城市 ii 与城市 jj 之间直接相连的那条道路的灰尘度的下限值。

输出格式

输出一行包含一个整数表示答案。

输入输出样例

输入 #1复制

3 10
0 2 4
2 0 1
4 1 0
0 2 2
2 0 0
2 0 0

输出 #1复制

2

思路:Floyd+二分答案

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,q,ans=1e7+5;
int m[1005][1005],min_xy[1005][1005],d[1005][1005],down[10005];
bool check(int x){
	int a=x/n,b=x%n;
	int sum=0;
	for(int i=1;i<=n;i++){
		down[i]=a;
		if(i<=b)down[i]++;
	}
	for(int i=1;i<=n;i++){//计算减少的灰尘度
		for(int j=1;j<=n;j++){
			d[i][j]=max(m[i][j]-down[i]-down[j],min_xy[i][j]);
		}
	}
	for(int k=1;k<=n;k++){//floyd
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			sum+=d[i][j];
		}
	}
	if(sum<=q)return true;
	else return false;
}
int main()
{
	cin>>n>>q;
	for(int i=1;i<=n;i++){//读入i与j相连的灰尘度
		for(int j=1;j<=n;j++){
			cin>>m[i][j];
		}
	}
	for(int i=1;i<=n;i++){//读入最小的灰尘度
		for(int j=1;j<=n;j++){
			cin>>min_xy[i][j];
		}
	}
	int L=0,R=1e7;
	while(L<=R){//二分答案
		int mid=(L+R)/2;
		if(check(mid))R=mid-1;
		else L=mid+1;
		
	}
	if(L>1e7)cout<<-1<<endl;//永远不可能满足
	else cout<<L<<endl;
 	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值