【实(dou)力(bi)首(mai)发(meng)】第四次CCF软件能力认证题解
2016-08-30 20:50
323 查看
【实(dou)力(bi)首(mai)发(meng)】第四次CCF软件能力认证题解
这次的题总体上相对前三次偏简单。由于实力有限,就分析前四题。
试题编号: 201503-1
试题名称: 图像旋转
时间限制: 5.0s
内存限制: 256.0MB
问题描述:
问题描述
旋转是图像处理的基本操作,在这个问题中,你需要将一个图像逆时针旋转90度。
计算机中的图像表示可以用一个矩阵来表示,为了旋转一个图像,只需要将对应的矩阵旋转即可。
输入格式
输入的第一行包含两个整数n, m,分别表示图像矩阵的行数和列数。
接下来n行每行包含m个整数,表示输入的图像。
输出格式
输出m行,每行包含n个整数,表示原始矩阵逆时针旋转90度后的矩阵。
样例输入
2 3
1 5 3
3 2 4
样例输出
3 4
5 2
1 3
评测用例规模与约定
1 ≤ n, m ≤ 1,000,矩阵中的数都是不超过1000的非负整数。
实(dou)力(bi)分析:逆时针旋转90°就是将矩阵的第i行变为第i列,第j行变为第m+1-j列,分析出来就没什么问题了。其次很重要的就是输出格式,每行的最后一个数字之后是没有空格的。签到题100分到手。
本人源码:
#include<iostream>
using namespace std;
int in[1010][1010], out[1010][1010];
int main(){
int i, j, m, n;
cin>>n>>m;
for(i=1;i<=n;++i) for(j=1;j<=m;++j) cin>>in[i][j];
for(i=1;i<=n;++i) for(j=1;j<=m;++j) out[m+1-j][i]=in[i][j];
for(i=1;i<=m;++i) {
for(j=1;j<=n;++j){
if(j==1) cout<<out[i][j];
else cout<<' '<<out[i][j];
}
cout<<endl;
}
return 0;
}
试题编号: 201503-2
试题名称: 数字排序
时间限制: 1.0s
内存限制: 256.0MB
问题描述:
问题描述
给定n个整数,请统计出每个整数出现的次数,按出现次数从多到少的顺序输出。
输入格式
输入的第一行包含一个整数n,表示给定数字的个数。
第二行包含n个整数,相邻的整数之间用一个空格分隔,表示所给定的整数。
输出格式
输出多行,每行包含两个整数,分别表示一个给定的整数和它出现的次数。按出现次数递减的顺序输出。如果两个整数出现的次数一样多,则先输出值较小的,然后输出值较大的。
样例输入
12
5 2 3 3 1 3 4 2 5 2 3 5
样例输出
3 4
2 3
5 3
1 1
4 1
评测用例规模与约定
1 ≤ n ≤ 1000,给出的数都是不超过1000的非负整数。
实(dou)力(bi)分析:这题主要是结构体的二级排序吧(反正我是这样做的),用好algorithm里的sort(),把过程模拟下就行了。由于给出的数是非负整数,所以0也要考虑进去,并且输入的数不一定小于n,所以在排序时应该sort(a, a+1005, cmp)。[b]
本人源码:
[/b]
#include<iostream>
#include<algorithm>
using namespace std;
struct num{
int val;
int t;
};
bool cmp(num a, num b){
if(a.t != b.t) return a.t>b.t;
return a.val<b.val;
}
num a[1005];
int main(){
int n, i, x;
for(i=0;i<=1000;++i){
a[i].val = i;
}
cin>>n;
for(i=1;i<=n;++i){
cin>>x;
++a[x].t;
}
sort(a, a+1005, cmp);
for(i=0;i<=n;++i){
if(a[i].t==0) break;
cout<<a[i].val<<' '<<a[i].t<<endl;
}
return 0;
}
试题编号: 201503-3
试题名称: 节日
时间限制: 1.0s
内存限制: 256.0MB
问题描述:
问题描述
有一类节日的日期并不是固定的,而是以“a月的第b个星期c”的形式定下来的,比如说母亲节就定为每年的五月的第二个星期日。
现在,给你a,b,c和y1, y2(1850 ≤ y1, y2 ≤ 2050),希望你输出从公元y1年到公元y2年间的每年的a月的第b个星期c的日期。
提示:关于闰年的规则:年份是400的整数倍时是闰年,否则年份是4的倍数并且不是100的倍数时是闰年,其他年份都不是闰年。例如1900年就不是闰年,而2000年是闰年。
为了方便你推算,已知1850年1月1日是星期二。
输入格式
输入包含恰好一行,有五个整数a, b, c, y1, y2。其中c=1, 2, ……, 6, 7分别表示星期一、二、……、六、日。
输出格式
对于y1和y2之间的每一个年份,包括y1和y2,按照年份从小到大的顺序输出一行。
如果该年的a月第b个星期c确实存在,则以"yyyy/mm/dd"的格式输出,即输出四位数的年份,两位数的月份,两位数的日期,中间用斜杠“/”分隔,位数不足时前补零。
如果该年的a月第b个星期c并不存在,则输出"none"(不包含双引号)。
样例输入
5 2 7 2014 2015
样例输出
2014/05/11
2015/05/10
评测用例规模与约定
所有评测用例都满足:1 ≤ a ≤ 12,1 ≤ b ≤ 5,1 ≤ c ≤ 7,1850 ≤ y1, y2 ≤ 2050。
实(dou)力(bi)分析:有点麻烦的模拟题。更像小学的奥数题,总之把这题逻辑思路搞清楚了,一般过了样例就可以拿满分了。(l = min(y1), r = max(y2)也许纯属我的强迫症吧。。毕竟已经说了y1到y2年之间)[b]
本人源码:[/b]
#include<iostream>
using namespace std;
int day[2][13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
, 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool isRunNian(int y){
if(y%400==0) return true;
else if((y%4==0) && (y%100)) return true;
else return false;
}
int main(){
int y1, y2, a, b, c;
cin>>a>>b>>c>>y1>>y2;
int i, l = min(y1, y2), r = max(y1, y2);
for(i=l;i<=r;++i){
int curY = 1850;
int curM = 1;
int days = 0;
int xq = 1;
int d;
while(curY < i){
if(isRunNian(curY)) days+=366;
else days+=365;
++curY;
}
while(curM < a){
days += day[isRunNian(curY)][curM];
++curM;
}
xq = 1 + days%7;
if(xq > c) d =(c+7-xq)+(b-1)*7;
else d = (c-xq)+(b-1)*7;
if(d>day[isRunNian(curY)][curM]) cout<<"none"<<endl;
else {
cout<<curY<<'/';
if(a/10) cout<<a;
else cout<<'0'<<a;
cout<<'/';
if(d/10) cout<<d;
else cout<<'0'<<d;
cout<<endl;
}
}
return 0;
}
试题编号: 201503-4
试题名称: 网络延时
时间限制: 1.0s
内存限制: 256.0MB
问题描述:
问题描述
给定一个公司的网络,由n台交换机和m台终端电脑组成,交换机与交换机、交换机与电脑之间使用网络连接。交换机按层级设置,编号为1的交换机为根交换机,层级为1。其他的交换机都连接到一台比自己上一层的交换机上,其层级为对应交换机的层级加1。所有的终端电脑都直接连接到交换机上。
当信息在电脑、交换机之间传递时,每一步只能通过自己传递到自己所连接的另一台电脑或交换机。请问,电脑与电脑之间传递消息、或者电脑与交换机之间传递消息、或者交换机与交换机之间传递消息最多需要多少步。
输入格式
输入的第一行包含两个整数n, m,分别表示交换机的台数和终端电脑的台数。
第二行包含n - 1个整数,分别表示第2、3、……、n台交换机所连接的比自己上一层的交换机的编号。第i台交换机所连接的上一层的交换机编号一定比自己的编号小。
第三行包含m个整数,分别表示第1、2、……、m台终端电脑所连接的交换机的编号。
输出格式
输出一个整数,表示消息传递最多需要的步数。
样例输入
4 2
1 1 3
2 1
样例输出
4
样例说明
样例的网络连接模式如下,其中圆圈表示交换机,方框表示电脑:
其中电脑1与交换机4之间的消息传递花费的时间最长,为4个单位时间。
样例输入
4 4
1 2 2
3 4 4 4
样例输出
4
样例说明
样例的网络连接模式如下:
其中电脑1与电脑4之间的消息传递花费的时间最长,为4个单位时间。
评测用例规模与约定
前30%的评测用例满足:n ≤ 5, m ≤ 5。
前50%的评测用例满足:n ≤ 20, m ≤ 20。
前70%的评测用例满足:n ≤ 100, m ≤ 100。
所有评测用例都满足:1 ≤ n ≤ 10000,1 ≤ m ≤ 10000。
实(dou)力(bi)分析:图有 n+m个顶点,n+m-1条边,顶点之间两两连通,很容易看出来这是一棵树。问题抽象后就是求树中相距最远的两个叶子结点间的距离,这个距离又叫做树的直径。那天刚好带了求树的直径的模版过去,所以没动多少脑子就写完了。不过这题只拿了70分,模版的时间复杂度O(|V|+|E|)应该没什么问题,然后就想起了考试那天使用了cin来输入,在最后30%比较大输入量的评测用例中超时了,欲哭无泪,还是对大输入量不够敏感。模版的思路就是先dfs找出距离根结点0最远的叶子结点u,然后再对u一次dfs找出距离u最远的叶子结点。[b]
本人源码:[/b]
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N = 222222;
int edgeCount, firstEdge
, to
, length
, nextEdge
;
vector<int> dist;
void addEdge(int u, int v, int w){
to[edgeCount] = v;
length[edgeCount] = w;
nextEdge[edgeCount] = firstEdge[u];
firstEdge[u] = edgeCount++;
}
void dfs(int p, int u, int d){
dist[u] = d;
for(int iter = firstEdge[u]; iter != -1; iter = nextEdge[iter]){
if(to[iter] != p){
dfs(u, to[iter], d+length[iter]);
}
}
}
int getDiameter(int nodeCount, vector <pair <pair <int, int>, int> > edges){
edgeCount = 0;
memset(firstEdge, -1, sizeof(firstEdge));
for(vector<pair <pair <int, int>, int> >::iterator iter = edges.begin(); iter != edges.end();++iter){
addEdge(iter->first.first,iter->first.second, iter->second);
addEdge(iter->first.second,iter->first.first, iter->second);
}
dist.resize(nodeCount);
dfs(-1, 0, 0);
int u = max_element(dist.begin(), dist.end()) - dist.begin();
dfs(-1,u,0);
return *max_element(dist.begin(), dist.end());
}
int main(){
int n, m, v;
vector <pair <pair <int, int>, int> > edges;
scanf("%d%d",&n,&m);
for(int i=1;i<=n-1;++i){
scanf("%d",&v);
edges.push_back(make_pair(make_pair(v-1, i),1));
edges.push_back(make_pair(make_pair(i, v-1),1));
}
for(int i=n;i<=n+m-1;++i){
scanf("%d",&v);
edges.push_back(make_pair(make_pair(v-1, i),1));
edges.push_back(make_pair(make_pair(i, v-1),1));
}
printf("%d\n",getDiameter(n+m, edges));
return 0;
}
试题编号: 201503-5
试题名称: 最小花费
时间限制: 4.0s
内存限制: 256.0MB
问题描述:
问题描述
C国共有n个城市。有n-1条双向道路,每条道路连接两个城市,任意两个城市之间能互相到达。小R来到C国旅行,他共规划了m条旅行的路线,第i条旅行路线的起点是si,终点是ti。在旅行过程中,小R每行走一单位长度的路需要吃一单位的食物。C国的食物只能在各个城市中买到,而且不同城市的食物价格可能不同。
然而,小R不希望在旅行中为了购买较低价的粮食而绕远路,因此他总会选择最近的路走。现在,请你计算小R规划的每条旅行路线的最小花费是多少。
输入格式
第一行包含2个整数n和m。
第二行包含n个整数。第i个整数wi表示城市i的食物价格。
接下来n-1行,每行包括3个整数u, v, e,表示城市u和城市v之间有一条长为e的双向道路。
接下来m行,每行包含2个整数si和ti,分别表示一条旅行路线的起点和终点。
输出格式
输出m行,分别代表每一条旅行方案的最小花费。
样例输入
6 4
1 7 3 2 5 6
1 2 4
1 3 5
2 4 1
3 5 2
3 6 1
2 5
4 6
6 4
5 6
样例输出
35
16
26
13
样例说明
对于第一条路线,小R会经过2->1->3->5。其中在城市2处以7的价格购买4单位粮食,到城市1时全部吃完,并用1的价格购买7单位粮食,然后到达终点。
评测用例规模与约定
前10%的评测用例满足:n, m ≤ 20, wi ≤ 20;
前30%的评测用例满足:n, m ≤ 200;
另有40%的评测用例满足:一个城市至多与其它两个城市相连。
所有评测用例都满足:1 ≤ n, m ≤ 105,1 ≤ wi ≤ 106,1 ≤ e ≤ 10000。
实(dou)力(bi)分(mai)析(meng):看到时间限制是4s的那一刻对于做这道题我是拒绝的。不过前30%数据范围比较小,说说思路吧。先从si开始dfs找到通向ti的所有通路,然后dp找出最小花费。
事实证明写题解是件体力活,写完千万不要忘记保存,否则会重写一遍。。。
最后,吹一年的370镇楼。
Our Conquest is the Celestial Sea.
这次的题总体上相对前三次偏简单。由于实力有限,就分析前四题。
试题编号: 201503-1
试题名称: 图像旋转
时间限制: 5.0s
内存限制: 256.0MB
问题描述:
问题描述
旋转是图像处理的基本操作,在这个问题中,你需要将一个图像逆时针旋转90度。
计算机中的图像表示可以用一个矩阵来表示,为了旋转一个图像,只需要将对应的矩阵旋转即可。
输入格式
输入的第一行包含两个整数n, m,分别表示图像矩阵的行数和列数。
接下来n行每行包含m个整数,表示输入的图像。
输出格式
输出m行,每行包含n个整数,表示原始矩阵逆时针旋转90度后的矩阵。
样例输入
2 3
1 5 3
3 2 4
样例输出
3 4
5 2
1 3
评测用例规模与约定
1 ≤ n, m ≤ 1,000,矩阵中的数都是不超过1000的非负整数。
实(dou)力(bi)分析:逆时针旋转90°就是将矩阵的第i行变为第i列,第j行变为第m+1-j列,分析出来就没什么问题了。其次很重要的就是输出格式,每行的最后一个数字之后是没有空格的。签到题100分到手。
本人源码:
#include<iostream>
using namespace std;
int in[1010][1010], out[1010][1010];
int main(){
int i, j, m, n;
cin>>n>>m;
for(i=1;i<=n;++i) for(j=1;j<=m;++j) cin>>in[i][j];
for(i=1;i<=n;++i) for(j=1;j<=m;++j) out[m+1-j][i]=in[i][j];
for(i=1;i<=m;++i) {
for(j=1;j<=n;++j){
if(j==1) cout<<out[i][j];
else cout<<' '<<out[i][j];
}
cout<<endl;
}
return 0;
}
试题编号: 201503-2
试题名称: 数字排序
时间限制: 1.0s
内存限制: 256.0MB
问题描述:
问题描述
给定n个整数,请统计出每个整数出现的次数,按出现次数从多到少的顺序输出。
输入格式
输入的第一行包含一个整数n,表示给定数字的个数。
第二行包含n个整数,相邻的整数之间用一个空格分隔,表示所给定的整数。
输出格式
输出多行,每行包含两个整数,分别表示一个给定的整数和它出现的次数。按出现次数递减的顺序输出。如果两个整数出现的次数一样多,则先输出值较小的,然后输出值较大的。
样例输入
12
5 2 3 3 1 3 4 2 5 2 3 5
样例输出
3 4
2 3
5 3
1 1
4 1
评测用例规模与约定
1 ≤ n ≤ 1000,给出的数都是不超过1000的非负整数。
实(dou)力(bi)分析:这题主要是结构体的二级排序吧(反正我是这样做的),用好algorithm里的sort(),把过程模拟下就行了。由于给出的数是非负整数,所以0也要考虑进去,并且输入的数不一定小于n,所以在排序时应该sort(a, a+1005, cmp)。[b]
本人源码:
[/b]
#include<iostream>
#include<algorithm>
using namespace std;
struct num{
int val;
int t;
};
bool cmp(num a, num b){
if(a.t != b.t) return a.t>b.t;
return a.val<b.val;
}
num a[1005];
int main(){
int n, i, x;
for(i=0;i<=1000;++i){
a[i].val = i;
}
cin>>n;
for(i=1;i<=n;++i){
cin>>x;
++a[x].t;
}
sort(a, a+1005, cmp);
for(i=0;i<=n;++i){
if(a[i].t==0) break;
cout<<a[i].val<<' '<<a[i].t<<endl;
}
return 0;
}
试题编号: 201503-3
试题名称: 节日
时间限制: 1.0s
内存限制: 256.0MB
问题描述:
问题描述
有一类节日的日期并不是固定的,而是以“a月的第b个星期c”的形式定下来的,比如说母亲节就定为每年的五月的第二个星期日。
现在,给你a,b,c和y1, y2(1850 ≤ y1, y2 ≤ 2050),希望你输出从公元y1年到公元y2年间的每年的a月的第b个星期c的日期。
提示:关于闰年的规则:年份是400的整数倍时是闰年,否则年份是4的倍数并且不是100的倍数时是闰年,其他年份都不是闰年。例如1900年就不是闰年,而2000年是闰年。
为了方便你推算,已知1850年1月1日是星期二。
输入格式
输入包含恰好一行,有五个整数a, b, c, y1, y2。其中c=1, 2, ……, 6, 7分别表示星期一、二、……、六、日。
输出格式
对于y1和y2之间的每一个年份,包括y1和y2,按照年份从小到大的顺序输出一行。
如果该年的a月第b个星期c确实存在,则以"yyyy/mm/dd"的格式输出,即输出四位数的年份,两位数的月份,两位数的日期,中间用斜杠“/”分隔,位数不足时前补零。
如果该年的a月第b个星期c并不存在,则输出"none"(不包含双引号)。
样例输入
5 2 7 2014 2015
样例输出
2014/05/11
2015/05/10
评测用例规模与约定
所有评测用例都满足:1 ≤ a ≤ 12,1 ≤ b ≤ 5,1 ≤ c ≤ 7,1850 ≤ y1, y2 ≤ 2050。
实(dou)力(bi)分析:有点麻烦的模拟题。更像小学的奥数题,总之把这题逻辑思路搞清楚了,一般过了样例就可以拿满分了。(l = min(y1), r = max(y2)也许纯属我的强迫症吧。。毕竟已经说了y1到y2年之间)[b]
本人源码:[/b]
#include<iostream>
using namespace std;
int day[2][13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
, 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool isRunNian(int y){
if(y%400==0) return true;
else if((y%4==0) && (y%100)) return true;
else return false;
}
int main(){
int y1, y2, a, b, c;
cin>>a>>b>>c>>y1>>y2;
int i, l = min(y1, y2), r = max(y1, y2);
for(i=l;i<=r;++i){
int curY = 1850;
int curM = 1;
int days = 0;
int xq = 1;
int d;
while(curY < i){
if(isRunNian(curY)) days+=366;
else days+=365;
++curY;
}
while(curM < a){
days += day[isRunNian(curY)][curM];
++curM;
}
xq = 1 + days%7;
if(xq > c) d =(c+7-xq)+(b-1)*7;
else d = (c-xq)+(b-1)*7;
if(d>day[isRunNian(curY)][curM]) cout<<"none"<<endl;
else {
cout<<curY<<'/';
if(a/10) cout<<a;
else cout<<'0'<<a;
cout<<'/';
if(d/10) cout<<d;
else cout<<'0'<<d;
cout<<endl;
}
}
return 0;
}
试题编号: 201503-4
试题名称: 网络延时
时间限制: 1.0s
内存限制: 256.0MB
问题描述:
问题描述
给定一个公司的网络,由n台交换机和m台终端电脑组成,交换机与交换机、交换机与电脑之间使用网络连接。交换机按层级设置,编号为1的交换机为根交换机,层级为1。其他的交换机都连接到一台比自己上一层的交换机上,其层级为对应交换机的层级加1。所有的终端电脑都直接连接到交换机上。
当信息在电脑、交换机之间传递时,每一步只能通过自己传递到自己所连接的另一台电脑或交换机。请问,电脑与电脑之间传递消息、或者电脑与交换机之间传递消息、或者交换机与交换机之间传递消息最多需要多少步。
输入格式
输入的第一行包含两个整数n, m,分别表示交换机的台数和终端电脑的台数。
第二行包含n - 1个整数,分别表示第2、3、……、n台交换机所连接的比自己上一层的交换机的编号。第i台交换机所连接的上一层的交换机编号一定比自己的编号小。
第三行包含m个整数,分别表示第1、2、……、m台终端电脑所连接的交换机的编号。
输出格式
输出一个整数,表示消息传递最多需要的步数。
样例输入
4 2
1 1 3
2 1
样例输出
4
样例说明
样例的网络连接模式如下,其中圆圈表示交换机,方框表示电脑:
其中电脑1与交换机4之间的消息传递花费的时间最长,为4个单位时间。
样例输入
4 4
1 2 2
3 4 4 4
样例输出
4
样例说明
样例的网络连接模式如下:
其中电脑1与电脑4之间的消息传递花费的时间最长,为4个单位时间。
评测用例规模与约定
前30%的评测用例满足:n ≤ 5, m ≤ 5。
前50%的评测用例满足:n ≤ 20, m ≤ 20。
前70%的评测用例满足:n ≤ 100, m ≤ 100。
所有评测用例都满足:1 ≤ n ≤ 10000,1 ≤ m ≤ 10000。
实(dou)力(bi)分析:图有 n+m个顶点,n+m-1条边,顶点之间两两连通,很容易看出来这是一棵树。问题抽象后就是求树中相距最远的两个叶子结点间的距离,这个距离又叫做树的直径。那天刚好带了求树的直径的模版过去,所以没动多少脑子就写完了。不过这题只拿了70分,模版的时间复杂度O(|V|+|E|)应该没什么问题,然后就想起了考试那天使用了cin来输入,在最后30%比较大输入量的评测用例中超时了,欲哭无泪,还是对大输入量不够敏感。模版的思路就是先dfs找出距离根结点0最远的叶子结点u,然后再对u一次dfs找出距离u最远的叶子结点。[b]
本人源码:[/b]
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N = 222222;
int edgeCount, firstEdge
, to
, length
, nextEdge
;
vector<int> dist;
void addEdge(int u, int v, int w){
to[edgeCount] = v;
length[edgeCount] = w;
nextEdge[edgeCount] = firstEdge[u];
firstEdge[u] = edgeCount++;
}
void dfs(int p, int u, int d){
dist[u] = d;
for(int iter = firstEdge[u]; iter != -1; iter = nextEdge[iter]){
if(to[iter] != p){
dfs(u, to[iter], d+length[iter]);
}
}
}
int getDiameter(int nodeCount, vector <pair <pair <int, int>, int> > edges){
edgeCount = 0;
memset(firstEdge, -1, sizeof(firstEdge));
for(vector<pair <pair <int, int>, int> >::iterator iter = edges.begin(); iter != edges.end();++iter){
addEdge(iter->first.first,iter->first.second, iter->second);
addEdge(iter->first.second,iter->first.first, iter->second);
}
dist.resize(nodeCount);
dfs(-1, 0, 0);
int u = max_element(dist.begin(), dist.end()) - dist.begin();
dfs(-1,u,0);
return *max_element(dist.begin(), dist.end());
}
int main(){
int n, m, v;
vector <pair <pair <int, int>, int> > edges;
scanf("%d%d",&n,&m);
for(int i=1;i<=n-1;++i){
scanf("%d",&v);
edges.push_back(make_pair(make_pair(v-1, i),1));
edges.push_back(make_pair(make_pair(i, v-1),1));
}
for(int i=n;i<=n+m-1;++i){
scanf("%d",&v);
edges.push_back(make_pair(make_pair(v-1, i),1));
edges.push_back(make_pair(make_pair(i, v-1),1));
}
printf("%d\n",getDiameter(n+m, edges));
return 0;
}
试题编号: 201503-5
试题名称: 最小花费
时间限制: 4.0s
内存限制: 256.0MB
问题描述:
问题描述
C国共有n个城市。有n-1条双向道路,每条道路连接两个城市,任意两个城市之间能互相到达。小R来到C国旅行,他共规划了m条旅行的路线,第i条旅行路线的起点是si,终点是ti。在旅行过程中,小R每行走一单位长度的路需要吃一单位的食物。C国的食物只能在各个城市中买到,而且不同城市的食物价格可能不同。
然而,小R不希望在旅行中为了购买较低价的粮食而绕远路,因此他总会选择最近的路走。现在,请你计算小R规划的每条旅行路线的最小花费是多少。
输入格式
第一行包含2个整数n和m。
第二行包含n个整数。第i个整数wi表示城市i的食物价格。
接下来n-1行,每行包括3个整数u, v, e,表示城市u和城市v之间有一条长为e的双向道路。
接下来m行,每行包含2个整数si和ti,分别表示一条旅行路线的起点和终点。
输出格式
输出m行,分别代表每一条旅行方案的最小花费。
样例输入
6 4
1 7 3 2 5 6
1 2 4
1 3 5
2 4 1
3 5 2
3 6 1
2 5
4 6
6 4
5 6
样例输出
35
16
26
13
样例说明
对于第一条路线,小R会经过2->1->3->5。其中在城市2处以7的价格购买4单位粮食,到城市1时全部吃完,并用1的价格购买7单位粮食,然后到达终点。
评测用例规模与约定
前10%的评测用例满足:n, m ≤ 20, wi ≤ 20;
前30%的评测用例满足:n, m ≤ 200;
另有40%的评测用例满足:一个城市至多与其它两个城市相连。
所有评测用例都满足:1 ≤ n, m ≤ 105,1 ≤ wi ≤ 106,1 ≤ e ≤ 10000。
实(dou)力(bi)分(mai)析(meng):看到时间限制是4s的那一刻对于做这道题我是拒绝的。不过前30%数据范围比较小,说说思路吧。先从si开始dfs找到通向ti的所有通路,然后dp找出最小花费。
事实证明写题解是件体力活,写完千万不要忘记保存,否则会重写一遍。。。
最后,吹一年的370镇楼。
Our Conquest is the Celestial Sea.
相关文章推荐
- 第四次CCF计算机软件能力认证考试题解(Java)--201503--节日--100分通过
- 2015年3月CCF计算机软件能力认证题:节日
- CCF计算机软件能力认证模拟试题参考答案(JAVA)(201703 1+2)
- 第一届CCF计算机软件能力认证(一二两题)
- 2014年首届CCF软件能力认证试题第三题 .
- CCF计算机软件能力认证模拟试题(c/c++)
- CCF计算机软件能力认证试题练习-数列分段(Java参考答案学习记录)
- CCF计算机软件能力认证试题练习-相邻数对(Java参考答案学习记录)
- 以CCF CSP认证为抓手,积极探索软件基础能力递进式培养体系
- 2014年首届CCF软件能力认证试题 题目二
- 第一届CCF软件能力认证
- 201604-1折点计数——CCF计算机软件能力认证试题历届真题
- CCF软件能力认证上机考试指导书
- CCF计算机软件能力认证试题练习201312-1-出现次数最多的数
- 第六次CCF计算机软件能力认证考试题解(Java)--201512--数位之和--100分通过
- 第三次CCF计算机软件能力认证题目:Z字形扫描等(Java)
- 201709-1打酱油——CCF计算机软件能力认证试题历届真题
- 201512-1数位之和——CCF计算机软件能力认证试题历届真题
- CCF计算机软件能力认证试题练习-相反数(Java参考答案学习记录)
- 第三次CCF计算机软件能力认证考试题解(Java)--201412--Z字形扫描--100分通过