0000-0002 UVa227 Puzzles UVa232 Crossword Answers UVA1368 DNA Consensus String

UVa227 Puzzles

问题 ACM/ICPC World Finals 1993

在这里插入图片描述

在这里插入图片描述

代码&注释

/*
    Dreams never shine!
    It's you that shine while chasing your dreams :)
    JAYO!!
*/
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <assert.h>
using namespace std;

struct Point {
	int x, y;
	Point(int x = 0, int y = 0): x(x), y(y) {}
};
typedef Point Vector;

Vector operator + (const Vector& A, const Vector& B) {
	return Vector(A.x + B.x, A.y + B.y);
}

const int GSize = 5;
vector<string> grid;
Point ePos;
map<char, Vector> DIRS;

bool valid(const Point& p) {
	return p.x >= 0 && p.x < GSize && p.y >=0 && p.y < GSize;
}

void printGrid() {
	for (int i = 0; i < GSize; i++) {
		for (int j = 0; j < GSize; j++) {
			if (j) cout << ' ';
			cout << grid[i][j];
		}
		cout << endl;
	}
}

bool tryMove(char cmd) {
	// cout << "move " << cmd << ":" <<endl;
	if (!DIRS.count(cmd)) return false;
	assert(DIRS.count(cmd)); // 为假, 抛异常
	Point p = ePos + DIRS[cmd]; // 计算新空格的位置
	// p.x = ePos.x + DIRS[cmd].x;
	// p.y = ePos.y + DIRS[cmd].y;
	if (!valid(p)) return false;
	swap(grid[p.x][p.y], grid[ePos.x][ePos.y]); // 新空格处的值和原空格' ', 值交换
	ePos = p; // 更新 空格

	// printGrid();
	return true;
}

int main()
{
	int t = 1;
	string line;
	DIRS['A'] = Vector(-1, 0);
	DIRS['B'] = Vector(1, 0);
	DIRS['L'] = Vector(0, -1);
	DIRS['R'] = Vector(0, 1);
	while (true) {
		grid.clear();
		ePos.x = -1;
		ePos.y = -1;
		for (int i = 0; i < GSize; i++) {
			getline(cin, line);
			if (line == "Z") return 0;
			assert(line.size() == GSize); // 为真,不抛异常
			for (int j = 0; j < GSize; j++) { // 找到 空格, 定位给 ePos
				if (line[j] == ' ') {
					assert(ePos.x == -1 && ePos.y == -1); // 确保是初始化时的空格值
					ePos.x = i;
					ePos.y = j;
				}
			}
			grid.push_back(line); // 一行一行储存记录
		}
		char move;
		string moves;
		while (true) { // 记录下操作指令(上下左右之类的操作)
			getline(cin, line);
			assert(!line.empty());
			bool end = *(line.rbegin()) == '0'; // 判断是否输入结束值 0
			if (!end) moves.append(line);
			else moves.append(line, 0, line.size() - 1);
			if (end) break;
		}
		bool legal = true;
		for (int i = 0; i < moves.size(); i++) { // 开始执行指令
			if (!tryMove(moves[i])) {
				legal = false; 
				break;
			}			
		}
		if (t > 1) cout << endl;
			cout << "Puzzle #" << t++ << ":" << endl;
		if (legal) printGrid();
		else cout << "This puzzle has no final configuration." << endl;
	}
    return 0;
}


UVA232 Crossword Answers

问题 ACM/ICPC World Finals 1994

在这里插入图片描述

在这里插入图片描述

代码&注释

/*
    Dreams never shine!
    It's you that shine while chasing your dreams :)
    JAYO!!
*/
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <cstring>
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
using namespace std;

struct Point {
    int x, y;
    Point(int x = 0, int y = 0): x(x), y(y) {}
};
typedef Point Vector;
Vector operator + (const Vector& A, const Vector& B) {
    return Vector(A.x + B.x, A.y + B.y);
}
int R, C; // row, column
const int MAXC = 16;
char grid[MAXC][MAXC];

inline bool valid(const Point& p) {
    return p.x >= 0 && p.x < R && p.y >= 0 && p.y < C;
}

int main()
{
    char buf[MAXC];
    int bufLen;
    const Vector dLeft(0, -1), dUp(-1, 0), dRight(0, 1), dDown(1, 0);
    for (int t = 1; scanf("%d%d", &R, &C) == 2 && R; t++) {
        vector<Point> eligible;
        vector<int> down, across;

        if (t > 1) puts("");
        printf("puzzle #%d:\n", t); // #define _for(i, a, b) for (int i = (a); i < (b); ++i)
        _for(i, 0, R) {
            scanf("%s", grid[i]);
            _for(j, 0, C) {
                if (grid[i][j] == '*') continue;
                Point p(i, j), left = p + dLeft, up = p + dUp; // left 为左侧位置, up 为上
                bool isCross = !valid(left) || grid[left.x][left.y] == '*'; // 判断是否能作为为across起点
                bool isDown = !valid(up) || grid[up.x][up.y] == '*'; // 判断是否能作为为down起点
                if (isCross) across.push_back(eligible.size()); // 记录across起点所对应的数字编号 + 1(即eligible的末尾)
                if (isDown) down.push_back(eligible.size()); // 记录down起点所对应的数字编号 + 1(同上,该末尾即将插入p)
                if (isCross || isDown) eligible.push_back(p); // 存储p(Point p)(存储到末尾)
            }
        }

        puts("Across");
        for (auto n : across) { // n对应eligible中储存的cross起始点p的下标
            bufLen = 0;
            memset(buf, 0, sizeof(buf));
            Point p = eligible[n]; // 找到坐标(x, y)
            while (valid(p) && grid[p.x][p.y] != '*') {
                buf[bufLen++] = grid[p.x][p.y]; // 从grid中取得p对应的char值, 暂存在buff中
                p = p + dRight;
            }
            printf("%3d.%s\n", n + 1, buf); // n是从0开始的
        }
        puts("Down");
        for (auto n : down) {
            bufLen = 0;
            memset(buf, 0, sizeof(buf));
            Point p = eligible[n];
            while (valid(p) && grid[p.x][p.y] != '*') { // 确定down的重点(超出边界,遇到*, 终止)
                buf[bufLen++] = grid[p.x][p.y];
                p = p + dDown;
            }
            printf("%3d.%s\n", n + 1, buf);
        }
    }
    return 0;
}


知识点

inline

在c/c++中,为了解决一些频繁调用的
小函数大量消耗栈空间(栈内存)的问题,
特别的引入了inline修饰符,表示为内联函数,
栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。
在系统下,栈空间是有限的,假如频繁大量的使用就会造成因栈空间不足
而导致程序出错的问题,
如,函数的死循环递归调用的最终结果就是导致栈内存空间枯竭。

增加了 inline 关键字的函数称为“内联函数”。
内联函数和普通函数的区别在于:当编译器处理调用内联函数的语句时,
不会将该语句编译成函数调用的指令,
而是直接将整个函数体的代码插人调用语句处,
就像整个函数体在调用处被重写了一遍一样。

puts()

出字符串时都使用 printf(),
通过“%s”输出字符串。
其实还有更简单的方法,就是使用 puts() 函数。
使用 puts() 函数连换行符 '\n' 都省了,
使用 puts() 显示字符串时,系统会自动在其后添加一个换行符

UVA-1368 DNA Consensus String

问题 ACM/ICPC Seoul 2006

在这里插入图片描述

在这里插入图片描述

代码&注释

/*
    Dreams never shine!
    It's you that shine while chasing your dreams :)
    JAYO!!
*/
#include <iostream>
#include <string>
#include <vector>
#include <cassert>
#include <algorithm>
using namespace std;

struct ChCnt {
	int cnt; // 出现次数
	char c; // 字符
	void init(char ch = 'A') {
		c = ch;
		cnt = 0;
	}

	ChCnt() { init(); }
	bool operator < (const ChCnt& cc2) const {
		return cnt > cc2.cnt || (cnt == cc2.cnt && c < cc2.c);
	}
};

int main()
{
	int T = 1, m, n;
	cin >> T;
	string line;
	vector<string> seqs;
	char IDX[256] = {0};
	IDX['A'] = 0; 
	IDX['C'] = 1;
	IDX['G'] = 2;
	IDX['T'] = 3;
	while (T--) {
		seqs.clear();
		cin >> m >> n;
		for (int i = 0; i < m; i++) { // 存储数据
			cin >> line;
			assert(line.size() == n);
			seqs.push_back(line);
		}
		string ansStr; 
		int ans = 0;
		vector<ChCnt> ccs(4);
		for (int i = 0; i < n; i++) { // 一列一列的处理
			ccs[0].init('A'); // 初始化(用来统计的变量)
			ccs[1].init('C');
			ccs[2].init('G');
			ccs[3].init('T');
			for (int j = 0; j < m; j++) { // 每一列逐行增加(进行统计)
				ccs[IDX[seqs[j][i]]].cnt++;
			}
			sort(ccs.begin(), ccs.end());  // 先按照出现次数再按字符进行排序
			ansStr += ccs.front().c; // 得到排序后的首字母, 拼接到作为答案的字符串中
			ans += (m - ccs.front().cnt); // 得到得到每一列字符不同的行数
		}

		cout << ansStr << endl << ans << endl;
	}
    return 0;
}


小结论

刷题目记录下来!!!
记在小本子上!!!
算法竞赛入门经典
买了这么多天,你
入门了吗???

加油,专注,结合书籍,把书本上的系统学习吸收,反复巩固,多刷几遍!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值