文章目录
前言
提示:代码以AC,如果没有会在代码前进行说明
系列文章目录
一、蔡老板的会议
题目描述
图灵杯个人赛就要开始了,蔡老板召集俱乐部各部门的部长开会。综合楼有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;
}
最后,欢迎私信交流学习