灵动ICPC冬令营基础-6

A - The Blocks Problem

题目

在这里插入图片描述

Many areas of Computer Science use simple, abstract domains for both analytical and empirical studies. For example, an early AI study of planning and robotics (STRIPS) used a block world in which a robot arm performed tasks involving the manipulation of blocks.
In this problem you will model a simple block world under certain rules and constraints. Rather than determine how to achieve a specified state, you will “program” a robotic arm to respond to a limited set of commands.
The problem is to parse a series of commands that instruct a robot arm in how to manipulate blocks that lie on a flat table. Initially there are n blocks on the table (numbered from 0 to n-1) with block bi adjacent to block bi+1 for all 0 <= i < n-1 as shown in the diagram below:

The valid commands for the robot arm that manipulates blocks are:

move a onto b
where a and b are block numbers, puts block a onto block b after returning any blocks that are stacked on top of blocks a and b to their initial positions.

move a over b
where a and b are block numbers, puts block a onto the top of the stack containing block b, after returning any blocks that are stacked on top of block a to their initial positions.

pile a onto b
where a and b are block numbers, moves the pile of blocks consisting of block a, and any blocks that are stacked above block a, onto block b. All blocks on top of block b are moved to their initial positions prior to the pile taking place. The blocks stacked above block a retain their order when moved.

pile a over b
where a and b are block numbers, puts the pile of blocks consisting of block a, and any blocks that are stacked above block a, onto the top of the stack containing block b. The blocks stacked above block a retain their original order when moved.

quit
terminates manipulations in the block world.

Any command in which a = b or in which a and b are in the same stack of blocks is an illegal command. All illegal commands should be ignored and should have no affect on the configuration of blocks.

Input
The input begins with an integer n on a line by itself representing the number of blocks in the block world. You may assume that 0 < n < 25.
The number of blocks is followed by a sequence of block commands, one command per line. Your program should process all commands until the quit command is encountered.

You may assume that all commands will be of the form specified above. There will be no syntactically incorrect commands.
Output
The output should consist of the final state of the blocks world. Each original block position numbered i ( 0 <= i < n where n is the number of blocks) should appear followed immediately by a colon. If there is at least a block on it, the colon must be followed by one space, followed by a list of blocks that appear stacked in that position with each block number separated from other block numbers by a space. Don’t put any trailing spaces on a line.

There should be one line of output for each block position (i.e., n lines of output where n is the integer on the first line of input).
Sample Input

10
move 9 onto 1
move 8 over 1
move 7 over 1
move 6 over 1
pile 8 over 6
pile 8 over 5
move 2 over 1
move 4 over 9
quit

Sample Output

0: 0
1: 1 9 2 4
2:
3: 3
4:
5: 5 8 7 6
6:
7:
8:
9:

解析

本题用vector容器vector v[24]来表示木块,相当于一个二维数组,列确定,每列的行(木块数)不确定;并基于操作指令的规则,用vector容器的成员函数模拟对这些木块进行的操作。
首先,设计两个函数:find_pile_height(int a, int &p, int &h),返回木块a所在的堆号p以及a的高度h;clear_above(int p, int h),把第p堆第h个木块以上的木块放置到原来位置。然后,在这两个函数,以及vector容器的成员函数size()和push_back()的基础上,根据操作指令的规则,每种操作指令都用一个函数实现。最后,在主程序中逐条实现操作指令。
容器deque和容器vector都是序列式容器,都是采用动态数组来管理元素,能够快速地随机访问任一个元素,并且能够在容器的尾部快速地插入和删除元素。不同之处在于,deque还可以在容器首部快速地插入、删除元素。因此,容器deque也被称为双端队列。
使用deque容器之前要加上头文件:#include。

代码

#include <iostream>
#include <string>
#include <vector>
using namespace std;
int n;
vector <int> v[24];
void find_pile_height(int a, int &p, int &h) {
    
    
	for(p=0;p<n;p++)
		for(h=0;h<v[p].size();h++)
			if(v[p][h]==a) return;
}
void clear_above(int p, int h) {
    
    
	int i, b;
	for(i=h+1;i<v[p].size();i++) {
    
    
		b=v[p][i];
		v[b].push_back(b);
	}
	v[p].resize(h+1);
}
void moveonto(int a, int b) {
    
    
	int pa, ha, pb, hb;
	find_pile_height(a, pa, ha);
	find_pile_height(b, pb, hb);
	if(pa!=pb) {
    
    
		clear_above(pa, ha);
		clear_above(pb, hb);
		v[pb].push_back(a);
		v[pa].resize(ha);
	}
}
void moveover(int a, int b) {
    
    
	int pa, ha, pb, hb;
	find_pile_height(a, pa, ha);
	find_pile_height(b, pb, hb);
	if(pa!=pb) {
    
    
		clear_above(pa, ha);
		v[pb].push_back(a);
		v[pa].resize(ha);
	}
}
void pileonto(int a, int b) {
    
    
	int pa, ha, pb, hb, i;
	find_pile_height(a, pa, ha);
	find_pile_height(b, pb, hb);
	if(pa!=pb) {
    
    
		clear_above(pb, hb);
		for(i=ha;i<v[pa].size();i++) {
    
    
			v[pb].push_back(v[pa][i]);
		}
		v[pa].resize(ha);
	}
}
void pileover(int a, int b) {
    
    
	int pa, ha, pb, hb, i;
	find_pile_height(a, pa, ha);
	find_pile_height(b, pb, hb);
	if(pa!=pb) {
    
    
		for(i=ha;i<v[pa].size();i++) {
    
    
			v[pb].push_back(v[pa][i]);
		}
		v[pa].resize(ha);
	}
}
int main() {
    
    
	int i, j, a, b;
	string str1, str2;
	cin>>n;
	for(i=0;i<n;i++) {
    
    
		v[i].push_back(i);
	}
	cin>>str1;
	while(str1!="quit") {
    
    
		cin>>a>>str2>>b;
		if(str1=="move"&&str2=="onto") moveonto(a, b);
		if(str1=="move"&&str2=="over") moveover(a, b);
		if(str1=="pile"&&str2=="onto") pileonto(a, b);
		if(str1=="pile"&&str2=="over") pileover(a, b);
		cin>>str1;
	}
	for(i=0;i<n;i++) {
    
    
		printf("%d: ", i);
		for(j=0;j<v[i].size();j++) {
    
    
			printf("%d ", v[i][j]);
		}
		cout<<endl;
	}
	return 0;
} 

B - Broken Keyboard (a.k.a. Beiju Text)

题目

You’re typing a long text with a broken keyboard. Well it’s not so badly broken. The only problemwith the keyboard is that sometimes the “home” key or the “end” key gets automatically pressed(internally).
You’re not aware of this issue, since you’re focusing on the text and did not even turn on themonitor! After you finished typing, you can see a text on the screen (if you turn on the monitor).
In Chinese, we can call it Beiju. Your task is to find the Beiju text.
Input
There are several test cases. Each test case is a single line containing at least one and at most 100,000letters, underscores and two special characters ‘[’ and ‘]’. ‘[’ means the “Home” key is pressedinternally, and ‘]’ means the “End” key is pressed internally. The input is terminated by end-of-file(EOF).
Output
For each case, print the Beiju text on the screen.
Sample Input

This_is_a_[Beiju]_text
[[]][][]Happy_Birthday_to_Tsinghua_University

Sample Output

BeijuThis_is_a__text
Happy_Birthday_to_Tsinghua_University

解析

本题题意:对于每个输入的字符串,如果出现’ [ ‘,则输入光标就跳到 字符串的最前面,如果出现’ ] ‘,则输入光标就跳到字符串的最后面。输出实际上显示在屏幕上的字符串。
本题可以用双端队列模拟试题描述给出的规则,用字符串变量s存储输入的字符串,deque容器deque sp来产生在屏幕上的悲剧的文 本。在输入字符串s后,对s中的字符逐个处理:当前字符如果不是’ [ ‘或’ ] ‘,则当前字符加入到中间字符串t中(t+=s[i]);当前字符如果是’ [ ‘,则中间字符串t的内容插入到deque容器sp的首部;当前字符如果是’ ] ',则中间字符串t的内容插入到deque容器sp的尾部。
最后,从deque容器sp中逐个输出字符。
本题的参考程序用到字符串操作函数clear(),删除全部字符;size(),返回字符数量;以及c_str(),将内容以C_string返回。

代码

#include <iostream>
#include <deque>
using namespace std;
string s, t;
deque <string> sp;
int main() {
    
    
	int i, j;
	while(cin>>s) {
    
    
		char a=0;
		t.clear();
		for(i=0;i<s.size();i++) {
    
    
			if(s[i]=='['||s[i]==']') {
    
    
				if(a=='[') sp.push_front(t);
				else sp.push_back(t);
				t.clear();
				a=s[i];
			}
			else t+=s[i];
			if(i==s.size()-1) {
    
    
				if(a=='[') sp.push_front(t);
				else sp.push_back(t);
				t.clear();
			}
		}
		while(!sp.empty()) {
    
    
			printf("%s", sp.front().c_str());
			sp.pop_front();
		}
		puts("");
	}
	return 0;
} 

C - Babelfish

题目

You have just moved from Waterloo to a big city. The people here speak an incomprehensible dialect of a foreign language. Fortunately, you have a dictionary to help you understand them.
Input
Input consists of up to 100,000 dictionary entries, followed by a blank line, followed by a message of up to 100,000 words. Each dictionary entry is a line containing an English word, followed by a space and a foreign language word. No foreign word appears more than once in the dictionary. The message is a sequence of words in the foreign language, one word on each line. Each word in the input is a sequence of at most 10 lowercase letters.
Output
Output is the message translated to English, one word per line. Foreign words not in the dictionary should be translated as “eh”.
Sample Input

dog ogday
cat atcay
pig igpay
froot ootfray
loops oopslay

atcay
ittenkay
oopslay

Sample Output

cat
eh
loops

Hint
Huge input and output,scanf and printf are recommended.

解析

本题需要处理一对一(英文单词、外语单词)数据,所以使用map容器sp,key和value的类型是string。首先,输入词典,以外语单词为key,英文单词为value,在map中插入词条(sp[b]=a);然后,输入要查询的外语单词,从map容器sp中,获取英文单词(sp[b])。

代码

#include <iostream>
#include <map>
#include <string>
using namespace std;
map <string, string> sp;
char a[10], b[10], s[28];
int main() {
    
    
	while(gets(s)&&s[0]!='\0') {
    
    
		sscanf(s,"%s %s", a, b);
		sp[b]=a;
	}
	while(gets(s)&&s[0]!='\0') {
    
    
		sscanf(s, "%s", b);
		if(sp[b]!="\0") cout<<sp[b]<<endl;
		else puts("eh");
	}
	return 0;
} 

D - Ananagrams

题目

Most crossword puzzle fans are used to anagrams — groups of words with the same letters in different orders — for example OPTS, SPOT, STOP, POTS and POST. Some words however do not have this attribute, no matter how you rearrange their letters, you cannot form another word. Such words are called ananagrams, an example is QUIZ.
Obviously such definitions depend on the domain within which we are working; you might think that ATHENE is an ananagram, whereas any chemist would quickly produce ETHANE. One possible domain would be the entire English language, but this could lead to some problems. One could restrict the domain to, say, Music, in which case SCALE becomes a relative ananagram (LACES is not in the same domain) but NOTE is not since it can produce TONE.
Write a program that will read in the dictionary of a restricted domain and determine the relative ananagrams. Note that single letter words are, ipso facto, relative ananagrams since they cannot be “rearranged” at all. The dictionary will contain no more than 1000 words.
Input
Input will consist of a series of lines. No line will be more than 80 characters long, but may contain any number of words. Words consist of up to 20 upper and/or lower case letters, and will not be broken across lines. Spaces may appear freely around words, and at least one space separates multiple words on the same line. Note that words that contain the same letters but of differing case are considered to be anagrams of each other, thus ‘tIeD’ and ‘EdiT’ are anagrams. The file will be terminated by a line consisting of a single ‘#’.
Output
Output will consist of a series of lines. Each line will consist of a single word that is a relative ananagramin the input dictionary. Words must be output in lexicographic (case-sensitive) order. There will alwaysbe at least one relative ananagram.
Sample Input

ladder came tape soon leader acme RIDE lone Dreis peat
ScAlE orb eye Rides dealer NotE derail LaCeS drIed
noel dire Disk mace Rob dries
#

Sample Output

Disk
NotE
derail
drIed
eye
ladder
soon

解析

若当前单词的升序串与某单词的升序串相同,则说明该单词是相对变形词;若当前单词的升序串不同于所有其它单词的升序串,则该单词是非相对变形词。由此给出算法:
首先,通过函数getkey(string& s),输入的字符串s中的字母改为小写字母,并按字母升序排列;然后,在map容器dict中,用数组方式插入处理后的字符串,累计字符串的重复次数值;而输入的原始字符串添加到vector容器words中。接下来,对vector容器words中的每个字符串进行判断,如果是非相对变形词,则插入到vector容器ans中;最后,对vector容器ans中的所有相对非变形词按字典序进行排列,然后输出。

代码

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
map <string, int> sp;
vector <string> words;
vector <string> ans;
string getkey(string &s) {
    
    
	int i;
	string key=s;
	for(i=0;i<key.length();i++)
		key[i]=tolower(key[i]);
	sort(key.begin(), key.end());
	return key;
}
int main() {
    
    
	string s;
	int i;
	while(cin>>s&&s[0]!='#') {
    
    
		string key=getkey(s);
		sp[key]++;
		words.push_back(s);
	}
	for(i=0;i<words.size();i++)
		if(sp[getkey(words[i])]==1) ans.push_back(words[i]);
	sort(ans.begin(), ans.end());
	for(i=0;i<ans.size();i++) {
    
    
		cout<<ans[i]<<"\n";
	}
	return 0;
} 

E - The Spot Game

题目

在这里插入图片描述

The game of Spot is played on an N × N board as shown below for N = 4. During the game, alternate
players may either place a black counter (spot) in an empty square or remove one from the board, thus producing a variety of patterns. If a board pattern (or its rotation by 90 degrees or 180 degrees) is repeated during a game, the player producing that pattern loses and the other player wins. The game terminates in a draw after 2N moves if no duplicate pattern is produced before then.
Consider the following patterns: If the first pattern had been produced earlier, then any of the following three patterns (plus one other not shown) would terminate the game, whereas the last one would not.
Input
Input will consist of a series of games, each consisting of the size of the board, N (2 ≤ N ≤ 50) followed, on separate lines, by 2N moves, whether they are all necessary or not. Each move will consist of the coordinates of a square (integers in the range 1…N) followed by a blank and a character ‘+’ or ‘-’ indicating the addition or removal of a spot respectively. You may assume that all moves are legal, that is there will never be an attempt to place a spot on an occupied square, nor to remove a non-existent spot. Input will be terminated by a zero (0).
Output
Output will consist of one line for each game indicating which player won and on which move, or that
the game ended in a draw. See the Sample Output below for the exact format.
Sample Input

2
1 1 +
2 2 +
2 2 -
1 2 +
2
1 1 +
2 2 +
1 2 +
2 2 -
0

Sample Output

Player 2 wins on move 3
Draw

解析

在参考程序中,棋局表示为一个结构。每输入一个棋局,就将这一个棋局的四种旋转都存储在一个集合中。这样,对于棋局序列中的每个棋局,可以判断该棋局是否在集合中存在,如果已经存在,则根据步数判定赢家。走完2N步,没有重复棋局,则为平局。
由于set的具体实现采用了红黑树的平衡二叉树的数据结构,所以,set中的元素就有大小比较。在参考程序中,给出重载函数bool operator < (const spot& a, const spot& b),以比较两个结构的大小,便于在set中插入和查找元素。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<set>
using namespace std;
const int maxn = 55;
int n;
struct spot {
    
    
	bool arr[maxn][maxn];
}p;
bool operator < (const spot& a, const spot& b){
    
    
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++) {
    
    
			if(a.arr[i][j] < b.arr[i][j]) return true;
			else if(a.arr[i][j] > b.arr[i][j]) return false;
		}
	return false;
}
void change(spot& w) {
    
    
	spot a;
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++) {
    
    
			a.arr[i][j] = w.arr[j][n+1-i];
		}
	w = a;
}
int main() {
    
    
	int a, b;
	char c;
	while(scanf("%d", &n) && n) {
    
    
		bool flag = false;
		set<spot> s;
		memset(p.arr, false, sizeof(p.arr));
		int count = 0;
		for(int num=1; num<=2*n; num++) {
    
    
			scanf("%d%d %c\n", &a, &b, &c);
			if(flag) continue;
			if(c == '+') {
    
    
				p.arr[a][b] = true;
			}
			else p.arr[a][b] = false;
			if(s.count(p)) {
    
    
				flag =true;
				count = num;
				continue;
			}
			spot t(p);
			for(int j=0; j<4; j++) {
    
    
				s.insert(t);
				change(t);
			}
		}
		if(flag == true) {
    
    
			if(count % 2 == 0) printf("Player 1 wins on move %d\n", count);
			else printf("Player 2 wins on move %d\n", count);
		}
		else printf("Draw\n");
	}
	return 0;
}

F - Conformity

题目

Frosh commencing their studies at Waterloo have diverse interests, as evidenced by their desire to take various combinations of courses from among those available.

University administrators are uncomfortable with this situation, and therefore wish to offer a conformity prize to frosh who choose one of the most popular combinations of courses. How many frosh will win the prize?

Input
The input consists of several test cases followed by a line containing 0. Each test case begins with an integer 1 ≤ n ≤ 10000, the number of frosh. For each frosh, a line follows containing the course numbers of five distinct courses selected by the frosh. Each course number is an integer between 100 and 499.

The popularity of a combination is the number of frosh selecting exactly the same combination of courses. A combination of courses is considered most popular if no other combination has higher popularity.

Output
For each line of input, you should output a single line giving the total number of students taking some combination of courses that is most popular.

Sample Input

3
100 101 102 103 488
100 200 300 101 102
103 102 101 488 100
3
200 202 204 206 208
123 234 345 456 321
100 200 300 400 444
0

Sample Output

2
3

解析

有n位学生选课,每位学生选修5门课,有5个不同的课程号。要求找出选修最受欢迎的课程组合的学生数量;如果有多个课程组合是最受欢迎的,则计算选修这些组合的学生总数。
一个学生选课的5个不同的课程号,用STL的set(集合)容器s来存储;而n位学生选课,则STL的map容器count来存储,map将相同集合(相同的课程组合)存储在同一位置,在存入一个集合时,该集合出现次数增加1。同时,记录出现最多的课程组合的次数M,以及出现次数为a的课程组合数b。最后输出a*b。
注意:由于map复杂度过高容易超时,建议用set来标记遍历各种情况。

代码

#include <iostream>
#include <set>
#include <map>
using namespace std;
map<set<int>, int> count;
set <int> s;
int n, i, k, a, b, xh;
int main() {
    
    
	while(cin>>n, n) {
    
    
		a=0, b=0;
		while(n--) {
    
    
			for(i=0;i<5;i++) {
    
    
				cin>>xh;
				s.insert(xh);
			}
			count[s]++;
			k=count[s];
			if(k==a) b++;
			if(k>a) a=k, b=1;
		}
		cout<<a*b<<endl;
	}
	return 0;
} 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<set>
using namespace std;
const int maxn = 55;
int n;
struct spot {
    
    
	bool arr[maxn][maxn];
}p;
bool operator < (const spot& a, const spot& b){
    
    
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++) {
    
    
			if(a.arr[i][j] < b.arr[i][j]) return true;
			else if(a.arr[i][j] > b.arr[i][j]) return false;
		}
	return false;
}
void change(spot& w) {
    
    
	spot a;
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++) {
    
    
			a.arr[i][j] = w.arr[j][n+1-i];
		}
	w = a;
}
int main() {
    
    
	int a, b;
	char c;
	while(scanf("%d", &n) && n) {
    
    
		bool flag = false;
		set<spot> s;
		memset(p.arr, false, sizeof(p.arr));
		int count = 0;
		for(int num=1; num<=2*n; num++) {
    
    
			scanf("%d%d %c\n", &a, &b, &c);
			if(flag) continue;
			if(c == '+') {
    
    
				p.arr[a][b] = true;
			}
			else p.arr[a][b] = false;
			if(s.count(p)) {
    
    
				flag =true;
				count = num;
				continue;
			}
			spot t(p);
			for(int j=0; j<4; j++) {
    
    
				s.insert(t);
				change(t);
			}
		}
		if(flag == true) {
    
    
			if(count % 2 == 0) printf("Player 1 wins on move %d\n", count);
			else printf("Player 2 wins on move %d\n", count);
		}
		else printf("Draw\n");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_52328032/article/details/113146264