7-1 旅游规划
有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。
输入格式:
输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0~(N−1);M是高速公路的条数;S是出发地的城市编号;D是目的地的城市编号。随后的M行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。
输出格式:
在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。
输入样例:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
输出样例:
3 40
实验代码
#include<stdio.h>
#include<queue>
#include<vector>
using namespace std;
struct Trip
{
int next;
int cost;
int dis;
};
vector<Trip> edge[501];
bool mark[501]; //标记
int dis[501];
int cost[501];
int main()
{
int n, m, S, T; //城市个数,高速公路条数,起点,终点
int i, j;
Trip temp;
int newP;
while (scanf("%d%d%d%d", &n, &m, &S, &T) != EOF)
{
if (n == 0 && m == 0)
break;
for (i = 0; i <= n; i++)
{
edge[i].clear(); //初始化邻接链表
dis[i] = -1;
mark[i] = false;
cost[i] = 0;
}
while (m--) //高速公路条数
{
int city1, city2, len, money;
scanf("%d%d%d%d", &city1, &city2, &len, &money);
temp.cost = money;
temp.next = city2;
temp.dis = len;
edge[city1].push_back(temp);
temp.next = city1;
edge[city2].push_back(temp); //无向图,故每条边信息都要添加到两个顶点的单链表中
}
dis[S] = 0;
mark[S] = 1;
newP = S; //起点为S
for (i = 1; i < n; i++)
{
for (j = 0; j < edge[newP].size(); j++)
{
//更新一个顶点对它的边表内结点的距离
int next = edge[newP][j].next;
int money = edge[newP][j].cost;
int len = edge[newP][j].dis;
if (mark[next] == true)
continue;
if (dis[next] == -1 || dis[next] > dis[newP] + len || ((dis[next] == dis[newP] + len) && (cost[next] > cost[newP] + money)))
{
dis[next] = dis[newP] + len;
cost[next] = cost[newP] + money;
}
}
int minx = 66666666;
for (j = 0; j <= n; j++)
{
//寻找这个顶点出发的最小值
if (mark[j] == true)
continue;
if (dis[j] == -1)
continue;
if (dis[j] < minx)
{
minx = dis[j];
newP = j;
}
}
mark[newP] = true;
}
printf("%d %d
", dis[T], cost[T]);
}
return 0;
}
7-3 彩虹瓶
彩虹瓶的制作过程(并不)是这样的:先把一大批空瓶铺放在装填场地上,然后按照一定的顺序将每种颜色的小球均匀撒到这批瓶子里。
假设彩虹瓶里要按顺序装 N 种颜色的小球(不妨将顺序就编号为 1 到 N)。现在工厂里有每种颜色的小球各一箱,工人需要一箱一箱地将小球从工厂里搬到装填场地。如果搬来的这箱小球正好是可以装填的颜色,就直接拆箱装填;如果不是,就把箱子先码放在一个临时货架上,码放的方法就是一箱一箱堆上去。当一种颜色装填完以后,先看看货架顶端的一箱是不是下一个要装填的颜色,如果是就取下来装填,否则去工厂里再搬一箱过来。
如果工厂里发货的顺序比较好,工人就可以顺利地完成装填。例如要按顺序装填 7 种颜色,工厂按照 7、6、1、3、2、5、4 这个顺序发货,则工人先拿到 7、6 两种不能装填的颜色,将其按照 7 在下、6 在上的顺序堆在货架上;拿到 1 时可以直接装填;拿到 3 时又得临时码放在 6 号颜色箱上;拿到 2 时可以直接装填;随后从货架顶取下 3 进行装填;然后拿到 5,临时码放到 6 上面;最后取了 4 号颜色直接装填;剩下的工作就是顺序从货架上取下 5、6、7 依次装填。
但如果工厂按照 3、1、5、4、2、6、7 这个顺序发货,工人就必须要愤怒地折腾货架了,因为装填完 2 号颜色以后,不把货架上的多个箱子搬下来就拿不到 3 号箱,就不可能顺利完成任务。 另外,货架的容量有限,如果要堆积的货物超过容量,工人也没办法顺利完成任务。例如工厂按照 7、6、5、4、3、2、1 这个顺序发货,如果货架够高,能码放 6 只箱子,那还是可以顺利完工的;但如果货架只能码放 5 只箱子,工人就又要愤怒了…… 本题就请你判断一下,工厂的发货顺序能否让工人顺利完成任务。
输入样例:
7 5 3
7 6 1 3 2 5 4
3 1 5 4 2 6 7
7 6 5 4 3 2 1
输出样例:
YES
NO
NO
实验代码
#include<iostream>
#include<stack>
using namespace std;
int main()
{
int n, m, k;
int num;
scanf("%d%d%d", &n, &m, &k);
while (k--)
{
stack <int> stk; //申请一个栈
int t = 1; //第一个编号
int flag = 0; //判断是否超出栈容量
for (int i = 0; i < n; i++)
{
scanf("%d", &num);
if (num == t) //刚来的正好是需要的
{
t++;
while (stk.size()) //如果不为空的话
{
if (stk.top() == t) //判断栈顶元素与需要的那个是否一致
{
stk.pop(); //是就出栈
t++; //需要的下一个+1;
}
else
break;
}
}
else //不是需要的
{
stk.push(num); //进栈
if (stk.size() > m)
flag = 1; ////如果栈的容量超出了给定范围,就标记一下。
//注意不能break,不然栈里面就有上一个的残留。
}
}
if (flag == 1 || t < n)
{
printf("NO
");
}
else
printf("YES
");
}
return 0;
}
7-4 德才论
宋代史学家司马光在《资治通鉴》中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人。凡取人之术,苟不得圣人,君子而与之,与其得小人,不若得愚人。”
现给出一批考生的德才分数,请根据司马光的理论给出录取排名。
输入格式:
输入第一行给出 3 个正整数,分别为:N(≤10
5
),即考生总数;L(≥60),为录取最低分数线,即德分和才分均不低于 L 的考生才有资格被考虑录取;H(<100),为优先录取线——德分和才分均不低于此线的被定义为“才德全尽”,此类考生按德才总分从高到低排序;才分不到但德分到线的一类考生属于“德胜才”,也按总分排序,但排在第一类考生之后;德才分均低于 H,但是德分不低于才分的考生属于“才德兼亡”但尚有“德胜才”者,按总分排序,但排在第二类考生之后;其他达到最低线 L 的考生也按总分排序,但排在第三类考生之后。
随后 N 行,每行给出一位考生的信息,包括:准考证号、德分、才分,其中准考证号为 8 位整数,德才分为区间 [0, 100] 内的整数。数字间以空格分隔。
输出格式:
输出第一行首先给出达到最低分数线的考生人数 M,随后 M 行,每行按照输入格式输出一位考生的信息,考生按输入中说明的规则从高到低排序。当某类考生中有多人总分相同时,按其德分降序排列;若德分也并列,则按准考证号的升序输出。
输入样例:
14 60 80
10000001 64 90
10000002 90 60
10000011 85 80
10000003 85 80
10000004 80 85
10000005 82 77
10000006 83 76
10000007 90 78
10000008 75 79
10000009 59 90
10000010 88 45
10000012 80 100
10000013 90 99
10000014 66 60
输出样例:
12
10000013 90 99
10000012 80 100
10000003 85 80
10000011 85 80
10000004 80 85
10000007 90 78
10000006 83 76
10000005 82 77
10000002 90 60
10000014 66 60
10000008 75 79
10000001 64 90
实验代码
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct node
{
int num; //考号
int de; //德分
int cai; //才分
};
int cmp(struct node a, struct node b)
{
if ((a.de + a.cai) != (b.de + b.cai))
return (a.de + a.cai) > (b.de + b.cai); //从大到小排序
else if (a.de != b.de)
return a.de > b.de; //从大到小排序
else
return a.num < b.num; //从小到大排序
}
int main()
{
int n, Low, High;
scanf("%d%d%d", &n, &Low, &High); //人数,最低线,最优线
vector<node>v[4]; //定义一个容器为v,可以放node实体
node temp;
int total = n; //达到最低人数
for (int i = 0; i < n; i++)
{
scanf("%d %d %d", &temp.num, &temp.de, &temp.cai);
if (temp.de < Low || temp.cai < Low) //德分和才分都 < 最低线
{
total--;
}
else if (temp.de >= High && temp.cai >= High) //德分才分不低于最低线,才德全尽
{
v[0].push_back(temp);
}
else if (temp.de >= High && temp.cai < High) //德分达到最优线,才分低于最优线,德胜才
{
v[1].push_back(temp);
}
else if (temp.de < High && temp.cai < High && temp.de >= temp.cai) //德才分均低于H,德分高于才分,才德兼亡
{
v[2].push_back(temp);
}
else //其他达到最低线的考生
{
v[3].push_back(temp);
}
}
printf("%d
", total); //达线人数
for (int i = 0; i < 4; i++) //四类考生
{
sort(v[i].begin(), v[i].end(), cmp); //排序,首地址;尾地址;比较函数,自定义,返回值bool型,小于(降序)
for (int j = 0; j < v[i].size(); j++)
{
printf("%d %d %d
", v[i][j].num, v[i][j].de, v[i][j].cai);
}
}
return 0;
}
7-5 两个有序序列的中位数
已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数。有序序列A0,A1,⋯,AN−1的中位数指A(N−1)/2的值,即第⌊(N+1)/2⌋个数(A0为第1个数)。
输入格式:
输入分三行。第一行给出序列的公共长度N(0<N≤100000),随后每行输入一个序列的信息,即N个非降序排列的整数。数字用空格间隔。
输出格式:
在一行中输出两个输入序列的并集序列的中位数。
输入样例1:
5
1 3 5 7 9
2 3 4 5 6
输出样例1:
4
输入样例2:
6
-100 -10 1 1 1 1
-50 0 2 3 4 5
输出样例2:
1
实验代码
#include <iostream> //将两个合并,输出中间那个
#include<stdio.h>
#include <algorithm>
using namespace std;
int main()
{
int N;
scanf("%d", &N);
int num[200002];
for (int i = 0; i < N * 2; i++)
{
scanf("%d", &num[i]);
}
sort(num, num + (N * 2));
printf("%d
", num[N-1]);
return 0;
}