第四届“图灵杯”NEUQ-ACM程序设计人赛真题重现


前言

提示:代码以AC,如果没有会在代码前进行说明


系列文章目录

第四届“图灵杯”NEUQ-ACM程序设计人赛真题重现

第五届“图灵杯”NEUQ-ACM程序设计个人赛真题重现

第六届“图灵杯”NEUQ-ACM程序设计人赛真题重现

第七届“图灵杯”NEUQ-ACM程序设计个人赛真题重现


一、蔡老板的会议

题目描述

图灵杯个人赛就要开始了,蔡老板召集俱乐部各部门的部长开会。综合楼有N (1<=N<=1000)间办公室,编号1~N每个办公室有一个部长在工(mo)作(yu),其中X号是蔡老板的办公室,会议也将在X(1<=X<=N)号办公室举行。综合楼的构造极其特殊,这N个办公室之间M(1<=M<=100,000)条单向走廊。通过第i条路将需要花费Ti(1<=Ti<=100)单位时间。
由于工作很忙,开完会之后各部长需要返回自己的办公室。他们会选择最短时间的最优路径。
为了合理安排接下来的工作,蔡老板想知道,【来回最久的】【!!!】那个部长在路上花费的时间是多少。

输入描述
第一行:用空格隔开的三个数N,M和X
接下来的M行:每行有用空格隔开的三个数Ai,Bi和Ti,表示从A点到B点花费的时间Ti

输出描述
一个int型的数,表示花费时间的最大值

样例输入
4 4 1
1 2 1
2 3 1
3 4 3
4 1 3

样例输出
8

分析

单向图求最短路径,果断Dijkstra

AC代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1005;
const int inf = 0x3f3f3f3f;
int n, m, x;
int mp1[maxn][maxn],mp2[maxn][maxn];
int dis1[maxn], dis2[maxn];
int visit[maxn];
 
void djsitela(int (*mp)[1005], int * dis)
{
	memset(visit,0,sizeof(visit));
	
	visit[x] = 1;
	
	for(int i = 1;i <= n;i ++)
	dis[i] = mp[x][i];
	
	for(int i = 1;i <= n;i ++)
	{
		int k = -1, minn = inf;
		for(int j = 1;j <= n;j ++)
		{
			if(!visit[j] && dis[j] < minn)
			{
				minn = dis[j];
				k = j;
			}
		}
		
		if(k == -1 )
		break;
		
		visit[k] = 1;
		
		for(int j = 1;j <= n;j ++)
		{
			if(!visit[j] && dis[j] > dis[k] + mp[k][j])
			dis[j] = dis[k] + mp[k][j];
		}
	}
} 
int main()
{
	
	while(cin >> n >> m >> x)
	{
		for(int i = 1;i <= n;i ++)
		{
			for(int j = 1;j <= n;j ++)
			{
				if(i == j) mp1[i][j] = mp2[i][j] = 0;
				else
				mp1[i][j] = mp2[i][j] = inf;
			}
		}
		
		int t1, t2, t3;
		for(int i = 1;i <= m;i ++)
		{
			cin >> t1 >> t2 >> t3;
			mp1[t1][t2] = t3;
			mp2[t2][t1] = t3;
		}
		
		djsitela(mp1,dis1);
		djsitela(mp2,dis2);
		
		for(int i = 1;i <= n;i ++)
		dis1[i] += dis2[i];
		
		sort(dis1 + 1,dis1 + n + 1);
		
		cout << dis1[n] << endl;
	}
	return 0;	
} 

二、拿糖果

题目描述

在这里插入图片描述

分析

编号由大到小找最小值并记录,然后求差值就好了

AC代码如下:

#include <iostream>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;
int n;
int map[100005];
int MIN[100005];
int main ()
{
	while (cin>>n)
	{
		
		for (int i=0;i<n;i++)
		{
			cin>>map[i];
		}
		MIN[n-1]=map[n-1];
		for (int i=n-2;i>=0;i--)
		{
			MIN[i]=min (MIN[i+1],map[i]);
			
		}
		int inf=-100010;
		for (int i=0;i<n-1;i++)
		{
			if (map[i]-MIN[i+1]>inf)
			{
				inf =map[i]-MIN[i+1];
			}
		}
		cout<<inf<<endl;
	}
	return 0;
	
}


三、粉丝与分割平面

题目描述

在一个平面上使用一条直线最多可以将一个平面分割成两个平面,而使用两条直线最多可将平面分割成四份,使用三条直线可将平面分割成七份……这是个经典的平面分割问题,但是too simple,作为一个可以对困难谈笑风生的人,我们现在将问题改一下,不再使用平面,而使用一个角来分割平面,一个角最多可以将平面分成两份,两个角最多可以将平面分成七份……那么n个角可以将平面分割成几个部分呢?再进一步,考虑用圆可以将平面分割成几部分呢?聪明的你肯定想得到,答案是…

输入描述
第一行一个正整数T(1<=T<=20)表示测试数据的数量,之后每行两个正整数n和m(1<=n,m<=1000)分别表示使用n个角和m个圆。

输出描述
每组数据输出两个答案s1和s2,分别表示使用n个角可将平面分割成s1份,使用m个圆可将平面分割成s2份

样例输入
2
1 1
2 3
样例输出
2 2
7 8

分析

参考文章:关于各种平面切割问题…

AC代码如下:

#include<iostream>
#include <cmath>
using namespace std;
int t;
int main ()
{
	cin>>t;
	while (t--)
	{
		int a,b;
		cin>>a>>b;
		cout<<2*a*a-a+1<<" ";
		cout<<b*b-b+2<<endl;
		 
	}
	return 0;
	
}


四、粉丝与汉诺塔

题目描述

苟利国家生死以,岂因福祸避趋之?作为ACM真正的粉丝,应该都听闻过汉诺塔问题,汉诺塔问题是这样的:
有三根柱子,编号A,B,C柱,初始情况下A柱上有n个盘子,小盘子在上大盘子在下,n个盘子大小各不一样,每次移动一个最上层的盘子算作一步,大盘子无法移动到小盘子上面,现在要把n个盘子从A柱全部移动到C柱,请问一共需要多少步?

现在对汉诺塔问题加以限制,每次移动只能经由中间柱实现,即是说如果想从A柱移动到C柱,只能A到B,然后B到C这样移动,反之亦然,那么请问,n个盘子从A柱全部移动到C柱一共需要多少步?

输入描述
多组输入,每组输入一个正整数n(1<=n<=18)

输出描述
每行输出一个正整数答案

样例输入
1
2
样例输出
2
8

分析

基础汉诺塔问题扩展,简单模拟就可以找到规律
步数:
map[1]=2;
map[i]=map[i-1]*3+2;(i>1)

AC代码如下:

#include<iostream>
#include <cmath>
using namespace std;
long long int map[20];
int main ()
{
	int n;
	map[1]=2;
	for (int i=2;i<20;i++)
	{
		map[i]=map[i-1]*3+2;
	}
	while (cin>>n)
	{
		cout<<map[n]<<endl;
		 
	}
	return 0;
	
}


五、完善“新谷密”

题目描述


在这里插入图片描述
在这里插入图片描述

不会吧不会吧不会真的有人做这道题吧(doge)


六、爬楼梯

题目描述

由于第m个台阶上有好吃的薯条,所以薯片现在要爬一段m阶的楼梯.
薯片每步最多能爬k个阶梯,但是每到了第i个台阶,薯片身上的糖果都会掉落a[i]个,现在问你薯片至少得掉多少糖果才能得到薯条?

输入描述
多组数据输入,每组数据第一行输入两个数字m(1<m<1000),k(1< k<m)接下来有m行,每一行输入a [i] (0<a[i]<1000),表示第i个台阶会掉落的糖果.

输出描述
对于每组数据,输出至少要牺牲的糖果数.

样例输入
5 2
1 2 3 4 5
6 2
6 5 4 3 2 1
样例输出
9
9
提示
开始的时候薯片站在第0个台阶

分析

动态规划

AC代码如下:

#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
const int INF=0x3f3f3f3f; 
int dp[1005];
int map[1005];
int main ()
{
	int m,k;
	while(cin>>m>>k)
	{
		
		for (int i=0;i<=m;i++)
		{
			dp[i]=INF;
		}
		memset (map,0,sizeof(map));
		dp[0]=0;
		for (int i=1;i<=m;i++)
		{
			cin>>map[i];
		}
		for (int i=1;i<=m;i++)
		{
			int T=i-k;
			if (T<0)
			{
				T=0;
			}
			for (int j=T;j<i;j++)
			{
				dp[i]=min(dp[i],dp[j]+map[i]);
			}
			
		}
		cout<<dp[m]<<endl;
		
		
		
		
		
		
	}
}

七、吃薯条

题目描述

薯片这次又遇到问题了=v=
薯片有n个薯条棒,第i个薯条棒的长度为i,由于薯片能瞬间移动,所以薯片能在1秒内从这n个薯条棒里面选择一个或者多个,吃掉同样长的一部分,
并且被吃掉部分的长度是正整数,问薯片至少多少时间能把这n个薯条棒都吃完?

输入描述
多组数据输入,每组数据第一行输入一个)n(1<n<10e9).

输出描述
对于每组数据,输出最短的时间.

样例输入
3
4
样例输出
2
3

分析

1 . 如果每次吃掉的薯条都是最多,那么就可以在最短的时间内吃完全部的薯条
2 . 假设有n个薯条,现在每个薯条一次性吃掉k长,且薯条长度不能是负数,所以吃掉的薯条最短是k长。那么一次性吃掉的总长度就是:k*(n-k+1);显然在k=(n+1)/2时 k*(n-k+1) 最大。
3 . 假设有6条薯条棒,则长度分别为1,2,3,4,5,6;由(2)此时k=3,吃掉k长后的长度分别是:1,2,0,1,2,3;此时 薯条最长是3;由样例知道吃掉长度最长3的薯条所需时间为2秒,所以吃掉长度最长6的薯条所需时间为3秒,
4 . 所以吃掉长度最长n的薯条所需的时间 f(n)=f((n+1)/2)+1,且f(0)=0,f(1)=1,f(2)=2

AC代码如下:

#include <iostream>
#include <cmath>
#include <queue>
using namespace std;
int main ()
{
	long long int n;
	while (cin>>n)
	{
		int sum=0;
		long long int a=n;
		while (a!=0)
		{
			sum++;
			a=a/2;
		}
		cout<<sum<<endl;                                                                    
	}
	return 0;
	
}

八、一个简单的问题

题目描述!

在这里插入图片描述

分析

暴力就好了

AC代码如下:

#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stdio.h>
using namespace std;

int main ()
{
	int n;
	while (cin>>n)
	{
		for (int i=1;i<=n;i++)
		{
			for(int j=i;j<n;j++)
			{
				cout<<" ";
			}
			for (int j=1;j<=i;j++)
			{
				printf ("%c",'A'+j-1);
			}
			for (int j=i-1;j>=1;j--)
			{
				printf ("%c",'A'+j-1);
			} 
			cout<<endl;
			
			
		}
	}
	return 0;
	
}

最后,欢迎私信交流学习
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值