1. 程式人生 > 其它 >靈動ICPC冬令營基礎-6

靈動ICPC冬令營基礎-6

靈動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;
}