机器翻译
题目背景
小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。
题目描述
这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换。对于每个英文单词,软件会先在内存中查找这个单词的中文含义,如果内存中有,软件就会用它进行翻译;如果内存中没有,软件就会在外存中的词典内查找,查出单词的中文含义然后翻译,并将这个单词和译义放入内存,以备后续的查找和翻译。
假设内存中有M个单元,每单元能存放一个单词和译义。每当软件将一个新单词存入内存前,如果当前内存中已存入的单词数不超过M-1,软件会将新单词存入一个未使用的内存单元;若内存中已存入M个单词,软件会清空最早进入内存的那个单词,腾出单元来,存放新单词。
假设一篇英语文章的长度为N个单词。给定这篇待译文章,翻译软件需要去外存查找多少次词典?假设在翻译开始前,内存中没有任何单词。
输入输出格式
输入格式:
输入文件共2行。每行中两个数之间用一个空格隔开。
第一行为两个正整数M和N,代表内存容量和文章的长度。
第二行为N个非负整数,按照文章的顺序,每个数(大小不超过1000)代表一个英文单词。文章中两个单词是同一个单词,当且仅当它们对应的非负整数相同。
输出格式:
包含一个整数,为软件需要查词典的次数。
输入输出样例
3 7 1 2 1 5 4 4 1
5
说明
每个测试点1s
对于10%的数据有M=1,N≤5。
对于100%的数据有0<=M<=100,0<=N<=1000。
整个查字典过程如下:每行表示一个单词的翻译,冒号前为本次翻译后的内存状况:
空:内存初始状态为空。
1. 1:查找单词1并调入内存。
2. 1 2:查找单词2并调入内存。
3. 1 2:在内存中找到单词1。
4. 1 2 5:查找单词5并调入内存。
5. 2 5 4:查找单词4并调入内存替代单词1。
6. 2 5 4:在内存中找到单词4。
7. 5 4 1:查找单词1并调入内存替代单词2。
共计查了5次词典。
思路:
纯的队列·模拟,若队列中的数多于n个,弹出队首元素;否则,若该数在队列中,忽略它,不在队中,入队。
代码:
#include<queue> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 1001 using namespace std; int n,m,x,ans; bool vis[N]; queue<int>q; int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch<='9'&&ch>='0'){x=x*10+ch-'0'; ch=getchar();} return x*f; } int main() { n=read(),m=read(); while(!q.empty()) q.pop(); while(m--) { x=read(); if(!vis[x]) { while(q.size()>=n) {vis[q.front()]=0; q.pop();} q.push(x); vis[x]=1; ans++; } } printf("%d",ans); }
关押罪犯
题目描述
S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c 的冲突事件。
每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。
在详细考察了N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。
那么,应如何分配罪犯,才能使Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?
输入输出格式
输入格式:
输入文件的每行中两个数之间用一个空格隔开。第一行为两个正整数N 和M,分别表示罪犯的数目以及存在仇恨的罪犯对数。接下来的M 行每行为三个正整数aj,bj,cj,表示aj 号和bj 号罪犯之间存在仇恨,其怨气值为cj。数据保证1<aj=<=bj<=N ,0 < cj≤ 1,000,000,000,且每对罪犯组合只出现一次。
输出格式:
共1 行,为Z 市长看到的那个冲突事件的影响力。如果本年内监狱中未发生任何冲突事件,请输出0。
输入输出样例
4 6 1 4 2534 2 3 3512 1 2 28351 1 3 6618 2 4 1805 3 4 12884
3512
说明
【输入输出样例说明】罪犯之间的怨气值如下面左图所示,右图所示为罪犯的分配方法,市长看到的冲突事件影响力是3512(由2 号和3 号罪犯引发)。其他任何分法都不会比这个分法更优。
【数据范围】对于30%的数据有N≤ 15。对于70%的数据有N≤ 2000,M≤ 50000。对于100%的数据有N≤ 20000,M≤ 100000。
思路:
本题我用的并查集做的。
先进行排序,然后最先在一个并查集中的(也就是在一个监狱中的)一定是所求结果
如果他们两个不在一个并查集中,那就把它独立让在一个监狱中。
代码:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 200001 using namespace std; bool vis[N]; int n,m,x,y,z,ans,tot; int fa[N],head[N]; struct Edge { int from,to,next,dis; }edge[N]; int cmp(Edge a,Edge b) { return a.dis>b.dis; } int add(int x,int y,int z) { tot++; edge[tot].from=x; edge[tot].to=y; edge[tot].dis=z; edge[tot].next=head[x]; head[x]=tot; } int find(int x) { if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch<='9'&&ch>='0'){x=x*10+ch-'0'; ch=getchar();} return x*f; } int main() { n=read(),m=read(); for(int i=1;i<=m;i++) { x=read(),y=read(),z=read(); add(x,y,z); } sort(edge+1,edge+1+m,cmp); for(int i=1;i<=(n<<1);i++) fa[i]=i; for(int i=1;i<=m;i++) { int t1=find(edge[i].from);//判断第一个人所处的监狱 int t2=find(edge[i].to);//第二个人所在的监狱 if(t1==t2)//这两个人在一个监狱中 { printf("%d",edge[i].dis);//因为排过序所以第一个发生冲突的就是所求答案 return 0; } fa[t2]=find(edge[i].from+n);//放入另一个监狱中 fa[t1]=find(edge[i].to+n); } printf("0"); return 0; }
乌龟棋
题目背景
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。
题目描述
乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。
乌龟棋中M张爬行卡片,分成4种不同的类型(M张卡片中不一定包含所有4种类型的卡片,见样例),每种类型的卡片上分别标有1、2、3、4四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。
游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。
很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。
现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?
输入输出格式
输入格式:
输入文件的每行中两个数之间用一个空格隔开。
第1行2个正整数N和M,分别表示棋盘格子数和爬行卡片数。
第2行N个非负整数,a1a2……aN,其中ai表示棋盘第i个格子上的分数。
第3行M个整数,b1b2……bM,表示M张爬行卡片上的数字。
输入数据保证到达终点时刚好用光M张爬行卡片。
输出格式:
输出只有1行,1个整数,表示小明最多能得到的分数。
输入输出样例
9 5 6 10 14 2 8 8 18 5 17 1 3 1 2 1
73
说明
每个测试点1s
小明使用爬行卡片顺序为1,1,3,1,2,得到的分数为6+10+14+8+18+17=73。注意,由于起点是1,所以自动获得第1格的分数6。
对于30%的数据有1≤N≤30,1≤M≤12。
对于50%的数据有1≤N≤120,1≤M≤50,且4种爬行卡片,每种卡片的张数不会超过20。
对于100%的数据有1≤N≤350,1≤M≤120,且4种爬行卡片,每种卡片的张数不会超过40;0≤ai≤100,1≤i≤N;1≤bi≤4,1≤i≤M。
思路:
这道题有很多人是用的搜索做的,然而我搜索学的不六(捂脸) 所以,蒟蒻只能尝试用dp做了
用dp怎么做?!
我们可以先将输入的卡片的数字存在一个step数组中,然后,用一个四维循环来找这个最大值。
如果他使用过一个类型卡片的话(同种类型的卡片使用起来先后顺序不都一样吗?!)那么她的上一个状态可能是这个状态减去他当前所在的步数,取最大值。
他当前所到达的点为1+i+j*2+K*3+l*4。为什么要加1? 因为他最开始就在一号位置啊!
最后输出 f[step[1]][step[2]][step[3]][step[4]]就好了
代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 500 using namespace std; int n,m,x,step[5]; int mark[N],f[50][50][50][50]; int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch<='9'&&ch>='0'){x=x*10+ch-'0'; ch=getchar();} return x*f; } int main() { n=read(),m=read(); for(int i=1;i<=n;i++) mark[i]=read(); for(int i=1;i<=m;i++) x=read(),step[x]++; for(int i=0;i<=step[1];i++) for(int j=0;j<=step[2];j++) for(int k=0;k<=step[3];k++) for(int l=0;l<=step[4];l++)//为什么从零开始? 因为你可以不用这个卡片啊! { if(i>0) f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k][l]); if(j>0) f[i][j][k][l]=max(f[i][j][k][l],f[i][j-1][k][l]); if(k>0) f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k-1][l]); if(l>0) f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k][l-1]); f[i][j][k][l]+=mark[i+j*2+k*3+l*4+1];//加上他当前所到达的位置上的分数 } printf("%d",f[step[1]][step[2]][step[3]][step[4]]); return 0; }
引水入城
题目描述
在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度。
为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。
因此,只有与湖泊毗邻的第1 行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。由于第N 行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。
输入输出格式
输入格式:
输入文件的每行中两个数之间用一个空格隔开。输入的第一行是两个正整数N 和M,表示矩形的规模。接下来N 行,每行M 个正整数,依次代表每座城市的海拔高度。
输出格式:
输出有两行。如果能满足要求,输出的第一行是整数1,第二行是一个整数,代表最少建造几个蓄水厂;如果不能满足要求,输出的第一行是整数0,第二行是一个整数,代表有几座干旱区中的城市不可能建有水利设施。
输入输出样例
【输入样例1】 2 5 9 1 5 4 3 8 7 6 1 2 【输入样例2】 3 6 8 4 5 6 4 4 7 3 4 3 3 3 3 2 2 1 1 2
【输出样例1】 1 1 【输出样例2】 1 3
说明
【样例1 说明】
只需要在海拔为9 的那座城市中建造蓄水厂,即可满足要求。
【样例2 说明】
数据范围
思路:
1.从上往下进行染色,然后统计第 n 行未被染色的数量 s ,若s>0,则输出 0 s;
为什么选择从上往下染色,而不是下方的从下往上染色,还能生一次搜索呢。(我买个关子,自己做的时候就知道了。)
2.从下往上进行两次染色,第一次,从左往右进行染色,得到每一个第一行的点所能覆盖的左界;
第二次,从右往左进行染色,得到每一个第一行的点所能覆盖的右界。
3.贪心。假设当前覆盖区间为[l,r],枚举第一行的点,从中选取能与当前区间[l,r]连接起来,并且向右延伸最远的点,作为下一个蓄水场建立点。
代码: