福建省信息学奥林匹克CCF NOIP夏令营第五天训练附解题思路及参考程序.docx

上传人:b****2 文档编号:23480979 上传时间:2023-05-17 格式:DOCX 页数:21 大小:21.94KB
下载 相关 举报
福建省信息学奥林匹克CCF NOIP夏令营第五天训练附解题思路及参考程序.docx_第1页
第1页 / 共21页
福建省信息学奥林匹克CCF NOIP夏令营第五天训练附解题思路及参考程序.docx_第2页
第2页 / 共21页
福建省信息学奥林匹克CCF NOIP夏令营第五天训练附解题思路及参考程序.docx_第3页
第3页 / 共21页
福建省信息学奥林匹克CCF NOIP夏令营第五天训练附解题思路及参考程序.docx_第4页
第4页 / 共21页
福建省信息学奥林匹克CCF NOIP夏令营第五天训练附解题思路及参考程序.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

福建省信息学奥林匹克CCF NOIP夏令营第五天训练附解题思路及参考程序.docx

《福建省信息学奥林匹克CCF NOIP夏令营第五天训练附解题思路及参考程序.docx》由会员分享,可在线阅读,更多相关《福建省信息学奥林匹克CCF NOIP夏令营第五天训练附解题思路及参考程序.docx(21页珍藏版)》请在冰豆网上搜索。

福建省信息学奥林匹克CCF NOIP夏令营第五天训练附解题思路及参考程序.docx

福建省信息学奥林匹克CCFNOIP夏令营第五天训练附解题思路及参考程序

 

2012福建省信息学奥林匹克CCFNOIP夏令营第五天训练

(附解题思路及参考程序)

 

问题名称

文件名

输入文件

输出文件

时限

分值

热浪

heatwv

heatwv.in

heatwv.out

1s

100

兽径管理

maintain

maintain.in

maintain.out

1s

100

无序字母对

pair

pair.in

pair.out

1s

100

请柬

invite

invite.in

invite.out

3s

100

内存限制均为256M

热浪(heatwv)

【问题描述】

德克萨斯纯朴的民眾们这个夏天正在遭受巨大的热浪!

他们的德克萨斯长角牛吃起来不错,可是他们并不是很擅长生產富含奶油的乳製品。

FarmerJohn此时以先天下之忧而忧,后天下之乐而乐的精神,身先士卒地承担起向德克萨斯运送大量的营养冰凉的牛奶的重任,以减轻德克萨斯人忍受酷暑的痛苦。

FJ已经研究过可以把牛奶从威斯康星运送到德克萨斯州的路线。

这些路线包括起始点和终点先一共经过T(1<=T<=2,500)个城镇,方便地标号為1到T。

除了起点和终点外地每个城镇由两条双向道路连向至少两个其它地城镇。

每条道路有一个通过费用(包括油费,过路费等等)。

给定一个地图,包含C(1<=C<=6,200)条直接连接2个城镇的道路。

每条道路由道路的起点Rs,终点Re(1<=Rs<=T;1<=Re<=T),和花费(1<=Ci<=1,000)组成。

求从起始的城镇Ts(1<=Ts<=T)到终点的城镇Te(1<=Te<=T)最小的总费用。

【输入文件】

第一行:

4个由空格隔开的整数:

T,C,Ts,Te

第2到第C+1行:

第i+1行描述第i条道路。

有3个由空格隔开的整数:

Rs,Re和Ci

【输出文件】

一个单独的整数表示从Ts到Te的最小总费用。

数据保证至少存在一条道路。

【样例输入】

71154

242

143

722

343

575

733

611

634

243

563

721

【样例输出】

7

【样例说明】

5->6->1->4(3+1+3)

兽径管理(maintain)

【问题描述】

约翰农场的牛群希望能够在N个(1<=N<=200)草地之间任意移动。

草地的编号由1到N。

草地之间有树林隔开。

牛群希望能够选择草地间的路径,使牛群能够从任一片草地移动到任一片其它草地。

牛群可在路径上双向通行。

牛群并不能创造路径,但是他们会保有及利用已经发现的野兽所走出来的路径(以下简称兽径)。

每星期他们会选择并管理一些或全部已知的兽径当作通路。

牛群每星期初会发现一条新的兽径。

他们接着必须决定管理哪些兽径来组成该周牛群移动的通路,使得牛群得以从任一草地移动到任一草地。

牛群只能使用当周有被管理的兽径做为通路。

牛群希望他们管理的兽径长度和为最小。

牛群可以从所有他们知道的所有兽径中挑选出一些来管理。

牛群可以挑选的兽径与它之前是否曾被管理无关。

兽径决不会是直线,因此连接两片草地之间的不同兽径长度可以不同。

此外虽然两条兽径或许会相交,但牛群非常的专注,除非交点是在草地内,否则不会在交点换到另外一条兽径上。

在每周开始的时候,牛群会描述他们新发现的兽径。

如果可能的话,请找出可从任何一草地通达另一草地的一组需管理的兽径,使其兽径长度和最小。

【输入文件】

输入的第一行包含两个用空白分开的整数N和W。

W代表你的程序需要处理的周数.(1<=W<=6000)。

以下每处理一周,读入一行数据,代表该周新发现的兽径,由三个以空白分开的整数分别代表该兽径的两个端点(两片草地的编号)与该兽径的长度(1…10000)。

一条兽径的两个端点一定不同。

【输出文件】

每次读入新发现的兽径后,你的程序必须立刻输出一组兽径的长度和,此组兽径可从任何一草地通达另一草地,并使兽径长度和最小。

如果不能找到一组可从任一草地通达另一草地的兽径,则输出“-1”。

【样例】

輸入

輸出

說明

46

1210

-1

Notrailconnects4totherestofthefields.

138

-1

Notrailconnects4totherestofthefields.

323

-1

Notrailconnects4totherestofthefields.

143

14

Maintain143,138,and323.

136

12

Maintain143,136,and323.

212

8

Maintain143,212,and323.

programexit

无序字母对(pair)

【问题描述】

给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。

请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。

【输入文件】

第一行输入一个正整数n。

以下n行每行两个字母,表示这两个字母需要相邻。

【输出文件】

输出满足要求的字符串。

如果没有满足要求的字符串,请输出“NoSolution”。

如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案

【样例输入】

4

aZ

tZ

Xt

aX

【样例输出】

XaZtX

【数据规模与约定】

不同的无序字母对个数有限,n的规模可以通过计算得到。

请柬(invite)

【问题描述】

在电视时代,没有多少人观看戏剧表演。

Malidinesia古董喜剧演员意识到这一事实,他们想宣传剧院,尤其是古色古香的喜剧片。

他们已经打印请帖和所有必要的信息和计划。

许多学生被雇来分发这些请柬。

每个学生志愿者被指定一个确切的公共汽车站,他或她将留在那里一整天,邀请人们参与。

  这里的公交系统是非常特殊的:

所有的线路都是单向的,连接两个站点。

公共汽车离开起始点,到达目的地之后又空车返回起始点。

 

学生每天早上从总部出发,乘公交车到一个预定的站点邀请乘客。

每个站点都被安排了一名学生。

在一天结束的时候,所有的学生都回到总部。

现在需要知道的是,学生所需的公交费用的总和最小是多少。

【输入文件】

第1行有两个整数n、m(1<=n,m<=1000000),n是站点的个数,m是线路的个数。

然后有m行,每行描述一个线路,包括3个整数,起始点,目的地和价格。

总部在第1个站点,价钱都是整数,且小于1000000000。

【输出文件】

输出一行,表示最小费用。

【样例输入】

46

1210

2160

1320

3410

245

4150

【样例输出】

210

【样例解释】

学生各自从总部被派遣到2,3,4站点,然后又回到总部

1-2-4-1:

10+5+50=65

1-3-4-1:

20+10+50=80

1-2-4-1:

10+5+50=65

65+80+65=210

【注意】

此题数据规模较大,需要使用较为高效的算法,此题不设小规模数据分数。

热浪:

基础的最短路问题

题目大意:

给出一张无向图,有T个点,C条边,求从Ts到Te的最短路。

解题思路:

这题是一个最基础的最短路问题,用于练习最短路算法,dijkstra或是spfa,都可以通过。

参考程序:

#include

#include

#include

#include

#include

usingnamespacestd;

constintMAXN=2501;

typedefvectorVec;

VecMap[MAXN],Val[MAXN];

intN,M,S,T;

voidinit()

{

scanf("%d%d%d%d\n",&N,&M,&S,&T);

inta,b,v;

for(inti=1;i<=M;i++)

{

scanf("%d%d%d\n",&a,&b,&v);

Map[a].push_back(b);

Val[a].push_back(v);

Map[b].push_back(a);

Val[b].push_back(v);

}

}

intdist[MAXN];

intflag[MAXN];

constintINF=1000000000;

queueQ;

voidSPFA()

{

for(inti=1;i<=N;i++)

dist[i]=INF,flag[i]=0;

dist[S]=0,flag[S]=1;

Q.push(S);

intt,tmp;

while(!

Q.empty())

{

t=Q.front();

Q.pop();

flag[t]=0;

for(unsignedinti=0;i

{

tmp=dist[t]+Val[t][i];

if(tmp

{

dist[Map[t][i]]=tmp;

if(!

flag[Map[t][i]])

{

Q.push(Map[t][i]);

flag[Map[t][i]]=1;

}

}

}

}

printf("%d\n",dist[T]);

return;

}

intmain()

{

freopen("heatwv.in","r",stdin);

freopen("heatwv.out","w",stdout);

init();

SPFA();

return0;

}

兽径管理:

对最小生成树算法的选择

题目大意:

有N个点,W条边,每输入一条边回答一次当前是否存在最小生成树及最小生成树长度和。

解题思路:

我们有两种常用的求最小生成树的算法

prim:

通过枚举点求最小生成树,每次的复杂度为O(N^2),可以使用二叉堆优化。

kruskal:

先将所有边排序,然后按长度从小到大选择,默认使用并查集,主要耗时为边的排序过程。

本题特点:

需要求W次最小生成树,每次仅增加1条边。

算法选择:

这题显然应该选择kruskal算法,因为每次只增加另一条边,只要插入之前已排序的部分即可完成排序过程。

由于利用了前一次的计算,W次kruskal的总时间降到了O(W^2),可以漂亮地通过该题。

在本题中,prim算法每次都需要重新计算,显然是十分费力的,不宜选择。

参考程序:

programmaintain;

constmaxn=200;

varn,m,t,i,j:

longint;

x,y,z:

array[0..6005]oflongint;

a,b,w:

longint;

f:

array[1..maxn]oflongint;

f1,f2:

longint;

ans:

longint;

proceduresort(xx,l,r,w:

longint);

vari,j:

longint;

begin

fori:

=0toxx-1do

if(z[i]<=w)and((w

forj:

=xxdowntoi+2do

begin

z[j]:

=z[j-1];

x[j]:

=x[j-1];

y[j]:

=y[j-1];

end;

z[i+1]:

=w;

x[i+1]:

=l;

y[i+1]:

=r;

end;

functiongetfa(x:

longint):

longint;

begin

iff[x]=0thenexit(x);

getfa:

=getfa(f[x]);

f[x]:

=getfa;

end;

begin

assign(input,'maintain.in');

assign(output,'maintain.out');

reset(input);

rewrite(output);

fillchar(x,sizeof(x),0);

fillchar(y,sizeof(y),0);

fillchar(z,sizeof(z),0);

readln(n,m);

fori:

=1tomdo

begin

fillchar(f,sizeof(f),0);

readln(a,b,w);

sort(i,a,b,w);

ans:

=0;

t:

=0;

forj:

=1toido

begin

f1:

=getfa(x[j]);

f2:

=getfa(y[j]);

iff1<>f2then

begin

f[f2]:

=f1;

inc(ans,z[j]);

inc(t);

end;

ift=n-1thenbreak;

end;

t:

=0;

forj:

=1tondo

iff[j]=0theninc(t);

ift<>1thenwriteln(-1)elsewriteln(ans);

end;

close(input);

close(output);

end.

无序字母对:

欧拉路径

题目描述:

给定n条边,每条边连接两个字母,求一条经过所有边的路径。

解题思路:

看清这道题的本质之后,这题是道典型的求欧拉路径问题,可以用来熟练欧拉路径的算法。

参考程序:

programccxcx;

varn,i,j:

longint;

c1,c2:

char;

g:

array[0..255,0..255]oflongint;

num:

array[0..255,0..255]oflongint;

vis:

array[0..255]ofboolean;

a:

array[0..10000]oflongint;

proceduredoit(v,now:

longint);

vari1:

longint;

begin

ifnow=n+2then

begin

fori1:

=1ton+1dowrite(chr(a[i1]));

writeln;

close(output);

halt;

end;

fori1:

=65to122do

ifnum[v,i1]>0then

begin

dec(num[v,i1]);

dec(num[i1,v]);

a[now]:

=i1;

doit(i1,now+1);

inc(num[v,i1]);

inc(num[i1,v]);

end;

end;

begin

assign(input,'pair.in');

assign(output,'pair.out');

reset(input);

rewrite(output);

readln(n);

fillchar(num,sizeof(num),0);

fillchar(g,sizeof(g),0);

fillchar(vis,sizeof(vis),false);

fori:

=1tondo

begin

readln(c1,c2);

inc(g[ord(c1),0]);

g[ord(c1),g[ord(c1),0]]:

=ord(c2);

inc(g[ord(c2),0]);

g[ord(c2),g[ord(c2),0]]:

=ord(c1);

inc(num[ord(c1),ord(c2)]);

inc(num[ord(c2),ord(c1)]);

vis[ord(c1)]:

=true;

vis[ord(c2)]:

=true;

end;

fori:

=0to255do

ifodd(g[i,0])then

begin

a[1]:

=i;

doit(i,2);

end;

fori:

=0to255do

ifvis[i]then

begin

a[1]:

=i;

doit(i,2);

end;

writeln('NoSolution');

close(input);

close(output);

end.

请柬:

dijkstra+二叉堆

题目大意:

有n个站点,m个单向的公交线路,n-1个学生从站点1出发乘公交分别前往站点2..n,再从各自的站点乘公交返回站点1,求最小的公交费用总和。

解题思路:

点1分别到点2..n的最短路即为学生出发时所需费用

使用单源最短路算法,即可求得一个点到其他所有点的最短路。

(如dijkstra)

将图反向后即可求学生返回时的费用

解题思路:

由于规模较大,这题需要使用dijkstra+二叉堆算法

将与起点的距离d数组放入堆中

每次使用堆快速获得最小的d[i]

参考程序:

#include

#include

#include

#include

#include

usingnamespacestd;

#defineFOR(i,a,b)for(inti=a;i<=b;i++)

#defineMST(a,b)memset(a,b,sizeof(a))

#defineMAXN2000050

#defineMAXM2000050

#defineMAXX1000000000

intn,m;

inttot,ue[MAXM],ve[MAXM],we[MAXM];

intfirst[MAXN],first2[MAXN],next[MAXM],next2[MAXM];

voidadd(intu,intv,intw)

{

ue[++tot]=u;ve[tot]=v;we[tot]=w;

next[tot]=first[u];first[u]=tot;

next2[tot]=first2[v];first2[v]=tot;

}

voidinit()

{

scanf("%d%d",&n,&m);

tot=0;

MST(first,0);MST(first2,0);

FOR(i,1,m)

{

intu,v,w;

scanf("%d%d%d",&u,&v,&w);

add(u,v,w);

}

}

intd[MAXN],b[MAXN];

intsize,heap[MAXN*2],hpos[MAXN*2];

voidheapfy(intk)

{

intmin=k,l=k<<1,r=(k<<1)+1;

if((l<=size)&&(d[heap[l]]

if((r<=size)&&(d[heap[r]]

if(min!

=k)

{

intt=heap[k];heap[k]=heap[min];heap[min]=t;

hpos[heap[k]]=k;hpos[heap[min]]=min;

heapfy(min);

}

}

voidexactheap()

{

heap[1]=heap[size];

size--;

hpos[heap[1]]=1;

heapfy

(1);

}

voidchange(intk)

{

heapfy(k);

intt=heap[k];

while((k>1)&&(d[t]>1]]))

{

heap[k]=heap[k>>1];

hpos[heap[k]]=k;

k=k>>1;

}

heap[k]=t;

hpos[heap[k]]=k;

}

voidpre()

{

size=0;

MST(heap,0);

}

longlongans;

voiddj()

{

FOR(i,2,n)d[i]=MAXX;

d[1]=0;

pre();

size=n;

FOR(i,1,n)

{

heap[i]=i;

hpos[i]=i;

}

FOR(i,1,n-1)

{

intk=heap[1];

exactheap();

for(intp=first[k];p!

=0;p=next[p])

if((d[k]+we[p]

{

d[ve[p]]=d[k]+we[p];

change(hpos[ve[p]]);

}

}

FOR(i,2,n)if(d[i]>=MAXX)printf("ERROR!

");

FOR(i,2,n)ans=ans+d[i];

}

voiddj2()

{

FOR(i,2,n)d[i]=MAXX;

d[1]=0;

pre();

size=n;

FOR(i,1,n)

{

heap[i]=i;

hpos[i]=i;

}

FOR(i,1,n-1)

{

intk=heap[1];

exactheap();

for(intp=first2[k];p!

=0;p=next2[p])

if((d[k]+we[p]

{

d[ue[p]]=d[k]+we[p];

change(hpos[ue[p]]);

}

}

FOR(i,2,n)if(d[i]>=MAXX)printf("ERROR!

");

FOR(i,2,n)ans=ans+d[i];

}

intmain()

{

freopen("invite.in","r",stdin);

freopen("invite.out","w",stdout);

//intnn;

//scanf("%d",&nn);

//FOR(ii,1,nn)

//{

init();

ans=0;

dj();

//cout<

dj2();

cout<

//}

}

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 高中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1