NOIP2010提高组复赛 解题报告(C/C++)(机械翻译)(乌龟棋)(关押罪犯)(引水入城)
来源:互联网 发布:three.js开发指南 pdf 编辑:程序博客网 时间:2024/04/29 17:18
2017.2.18日的练习赛(NOIP2010)
作为一个OI届的晚辈,能接触到近七年前的NOIP考试无疑是一件令人兴奋的事情。这倒不是因为什么信仰,实在是因为只有一试四道题(而不是二试六道题),做起来让人没有“后顾”之忧。下面我们来看看:
1.机械翻译
解题报告:
不得不说,这道题作为第一题是非常“温柔”的。众所周知,“模拟”算法(如果能称作一个算法的话)是NOIP最常考的考点(没有之一)。这道题就是对一个数据结构“队列”进行模拟。
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int N=1005;int n,m,tot=0;int head=1,tail=0,queue[N];//head头指针、tail尾指针、queue队列(用数组模拟)int main(){ freopen("translate.in","r",stdin); freopen("translate.out","w",stdout); memset(queue,0,sizeof(queue)); scanf("%d%d",&n,&m); while(m--) { int t; scanf("%d",&t); for(int i=head;i<=tail;i++) if(queue[i]==t)goto h; tot++; queue[++tail]=t; if(tail-head+1>n)head++;//内存占满的情况 h:; } printf("%d",tot); return 0;}
2.乌龟棋
解题报告:
看到这道题我就闻到了浓浓的动态规划的味道。众所周知,动态规划作为NOIP第二“关心”的考点,是不可能不会见到的(但是,囿于姿势水平太低,一开始是用dfs暴力做的(加上一点点剪枝))。这道题dp的思路是这样的:
先统计出走一步、两步、三步、四步的牌的个数。然后通过四个循环枚举每一种情况,这样来dp。
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int N=355;const int M=125;const int P=45;int n,m;int f[P][P][P][P],card[5],map[N];//f数组来dp,card数组来存储四种牌的个数、map来记录每一个点的点权。int main(){ memset(card,0,sizeof(card)); freopen("tortoise.in","r",stdin); freopen("tortoise.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&map[i]); for(int i=1;i<=m;i++) { int x; scanf("%d",&x); card[x]++; } f[0][0][0][0]=map[1];//赋f数组的第一个初值。 for(int i=0;i<=card[1];i++) for(int j=0;j<=card[2];j++) for(int k=0;k<=card[3];k++) for(int l=0;l<=card[4];l++)//dp过程 { int loc=i+j*2+k*3+l*4+1; if(i) f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k][l]+map[loc]); if(j) f[i][j][k][l]=max(f[i][j][k][l],f[i][j-1][k][l]+map[loc]); if(k) f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k-1][l]+map[loc]); if(l) f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k][l-1]+map[loc]); } printf("%d",f[card[1]][card[2]][card[3]][card[4]]); return 0;}
3.关押罪犯
解题报告:
这里可以把两个罪犯是否有关联抽象成一幅图,那么我们知道,图是用临界表存储的。这里就解决了存储问题。
此外,我们还需要用到并查集的思想,记录哪两个犯人不在一个监狱里面。如果我们把临界表按路权排好序(从小到大)过后,在不断放入的过程中,要是我们找到目前的一对已经被“安排”过了,就输出。不然的话,我们就将两个分别与对方的“镜像”安排在一起。
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int M=100005;const int N=40005;struct edge{ int u,w,v,next; edge(){next=-1; }};struct edge ed[M];int num=0;int head[N];int father[2*N];int n,m;void build(int u,int v,int w){ ++num; ed[num].u=u; ed[num].v=v; ed[num].w=w; ed[num].next=head[u]; head[u]=num;}bool cmp(const edge &a,const edge &b){ return a.w>b.w;}int getfather(int x)//并查集{ return father[x]==x?x:getfather(father[x]);}int main(){ freopen("prison.in","r",stdin); freopen("prison.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); build(u,v,w); } for(int i=1;i<=2*n;i++) father[i]=i; sort(ed+1,ed+m+1,cmp); for(int i=1;i<=m;i++) { int u=ed[i].u,v=ed[i].v; if(getfather(u)==getfather(v))//“被安排”过了 { printf("%d",ed[i].w); return 0; } father[getfather(v)]=getfather(ed[i].u+n);//“安排”一对罪犯。 father[getfather(u)]=getfather(ed[i].v+n); } printf("0"); return 0;}
4.引水入城
解题报告:
这道题我们将湖泊边的每一个城市能够在沙漠边“覆盖”到的区域弄成一个线段(这个通过深搜来实现),再通过简单的小dp(或者贪心也可以)来选择哪几座靠湖的城市最优(区间dp,线段覆盖)。需要注意的是,我们为了判定能否满足要求(是否需要输出0),可以通过一个广搜来判特。
#include<string.h>#include<stdio.h>#include<algorithm>using namespace std;const int N=500;int dir[5][2]={{0,1},{0,-1},{1,0},{-1,0}};struct loc{ int x,y;};struct loc queue[N*N];struct s{ int l,r;};struct s seg[N];int map[N+5][N+5],f[N+5];int flag[N+5][N+5];int n,m;int now,rest; void bfs()//广搜来判断是否能到 { int head=0,tail=0; for(int i=1;i<=m;i++) { flag[1][i]=1; queue[++tail].y=i; queue[tail].x=1; } do { head++; for(int i=0;i<=3;i++) { int x=queue[head].x+dir[i][0],y=queue[head].y+dir[i][1]; if(x>n&&x<1&&y>n&&y<1)continue; if(map[x][y]>map[queue[head].x][queue[head].y])continue; if(flag[x][y]==1)continue; queue[++tail].x=x; queue[++tail].y=y; flag[x][y]=1; } }while(head<tail);}void dfs(int x,int y)//深搜来更新能覆盖到的线段{ if(x==n) { seg[now].l=min(seg[now].l,y); seg[now].r=max(seg[now].r,y); } for(int i=0;i<=3;i++) { int x1=x+dir[i][0],y1=y+dir[i][1]; if(x1>n&&x1<1&&y1>n&&y1<1)continue; if(map[x1][y1]>map[x][y])continue; if(flag[x1][y1]==1)continue; flag[x1][y1]=1; dfs(x1,y1); flag[x1][y1]=0; }}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&map[i][j]); bfs();//判特 for(int i=1;i<=m;i++) if(!flag[1][i])rest++; if(rest)printf("0\n%d",rest);//判特 printf("1\n"); for(int i=1;i<=m;i++) { memset(flag,0,sizeof(flag)); now=i; seg[now].l=m+1; seg[now].r=0; flag[1][i]=1; dfs(1,i); } f[0]=0; for(int i=1;i<=m;i++) { f[i]=0x7fffffff; for(int j=1;j<=m;j++) if(i>=seg[j].l&&i<=seg[j].r) f[i]=min(f[i],f[seg[j].l-1]+1); } printf("%d",f[m]); return 0;}
以上
2017.2.22
0 0
- NOIP2010提高组复赛 解题报告(C/C++)(机械翻译)(乌龟棋)(关押罪犯)(引水入城)
- NOIP 2010 解题报告(机器翻译,乌龟棋,关押罪犯,引水入城)
- 关押罪犯 (NOIP2010)复赛 提高组 试题三 解题代码
- 4.引水入城 (NOIP2010)复赛 提高组 试题四 解题代码
- [NOIP2010]机器翻译,乌龟棋,关押罪犯,引水入城
- Noip 2010 解题报告(机器翻译,乌龟棋,关押罪犯,引水入城)
- 关押罪犯(noip2010)
- [noip模拟]四道题 noip2010 机器翻译 noip2010 乌龟棋 noip 关押罪犯 noip 引水入城
- NOIP2010 引水入城 解题报告(bfs+dp)
- NOIP2010提高组 关押罪犯 解题报告
- 乌龟棋 (NOIP2010)复赛 提高组 试题二 解题代码
- TYVJ1403(NOIP2010提高组T3)关押罪犯
- NOIP2010提高组 关押罪犯(并查集)
- NOIP2010提高组 引水入城(BFS)
- NOIP2010 关押罪犯 解题报告(并查集,补集判断思想)
- NOIP2010 提高组 复赛 prison 关押罪犯
- NOIP2010 关押罪犯(最大生成树)
- 【noip2010】引水入城(搜索+DP)
- 你可能需要这五种语言发布啦!
- string的那些坑
- j-link接口定义及实际使用
- java基础(5)--方法,字符串
- 从Java中的修饰符入手,浅谈类和继承的一些事儿
- NOIP2010提高组复赛 解题报告(C/C++)(机械翻译)(乌龟棋)(关押罪犯)(引水入城)
- Noip 2010 解题报告(机器翻译,乌龟棋,关押罪犯,引水入城)
- 服务端渲染、前端渲染、前后端同构
- 【NOIP2010】【贪心】【覆盖问题】T4 引水入城 题解
- Dockerfile 最佳实践
- mpeg2-ts协议分析
- 使用.net来搭建网站常用的一些实用知识
- Java输入输出流
- Retrofit的简单使用