[蓝桥杯] 刷题记录(2020.3.1)

翻硬币

源地址
在这里插入图片描述

输入

两行等长的字符串,分别表示初始状态和要达到的目标状态。每行的长度<1000

输出

一个整数,表示最小操作步数

样例输入

90

样例输出

5

代码

试想,每次翻就会翻好一个,其实直接翻就是最优的翻法

#include "iostream"
#include "cstring"
#include "algorithm"

using namespace std;

int main()
{
	int sum = 0;
	
	string str1, str2;
	
	cin >> str1 >> str2;
	
	for (int i = 0; i < str1.size(); i++)
	{
		if (str1[i] != str2[i])
		{
			// 翻转 
			if (!(str1[i] ^ 'o'))
			{
				str1[i] = '*';
			}
			else
			{
				str1[i] = 'o';
			}
			if (!(str1[i + 1] ^ 'o'))
			{
				str1[i + 1] = '*';
			}
			else
			{
				str1[i + 1] = 'o';
			}
			sum++;
		}
	}

	cout << sum;
	
	return 0;
}

哈夫曼树

源地址
Huffman树在编码中有着广泛的应用。在这里,我们只关心Huffman树的构造过程。
给出一列数{pi}={p0, p1, …, pn-1},用这列数构造Huffman树的过程如下:

  1. 找到{pi}中最小的两个数,设为pa和pb,将pa和pb从{pi}中删除掉,然后将它们的和加入到{pi}中。这个过程的费用记为pa+ pb。
  2. 重复步骤1,直到{pi}中只剩下一个数。

在上面的操作过程中,把所有的费用相加,就得到了构造Huffman树的总费用。

本题任务:对于给定的一个数列,现在请你求出用该数列构造Huffman树的总费用。

例如,对于数列{pi}={5, 3, 8, 2, 9},Huffman树的构造过程如下:

  1. 找到{5, 3, 8, 2, 9}中最小的两个数,分别是2和3,从{pi}中删除它们并将和5加入,得到{5, 8, 9, 5},费用为5。

  2. 找到{5, 8, 9, 5}中最小的两个数,分别是5和5,从{pi}中删除它们并将和10加入,得到{8, 9, 10},费用为10。

  3. 找到{8, 9, 10}中最小的两个数,分别是8和9,从{pi}中删除它们并将和17加入,得到{10, 17},费用为17。

  4. 找到{10, 17}中最小的两个数,分别是10和17,从{pi}中删除它们并将和27加入,得到{27},费用为27。

  5. 现在,数列中只剩下一个数27,构造过程结束,总费用为5+10+17+27=59。

输入

输入的第一行包含一个正整数n(n<=100)。
接下来是n个正整数,表示p0, p1, …, pn-1,每个数不超过1000。

输出

输出用这些数构造Huffman树的总费用。

样例输入

5
5 3 8 2 9

样例输出

59

代码
#include "iostream"
#include "string"
#include "algorithm"

using namespace std;

int main()
{
	int n, sum = 0;

	cin >> n;
	
	int *a = new int[n];
	
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
	}
	sort(a, a + n);
	for (int i = 1; i < n; i++)
	{
		a[i] = a[i] + a[i - 1];
		sum += a[i];
		sort(a + i, a + n);
	}
	cout << sum;
	
	return 0;
}

2n皇后问题

源地址

给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。

输入

输入的第一行为一个整数n,表示棋盘的大小。
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。

输出

输出一个整数,表示总共有多少种放法。

样例输入

4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1

样例输出

2

代码
#include "iostream"
#include "cstring"
#include "math.h"

using namespace std;

class Game{
public:
	int n;
	int count;	
	int blackQueen[8];
	int whiteQueen[8];
	int chessBoard[8][8];
	
	void init ()
	{
		cin >> n;
		count = 0;
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				cin >> chessBoard[i][j];
			}		
		}	
	}
	
	int placeBlackQueen (int k)
	{
		for (int i = 0; i < k - 1; i++)
		{
			int flag = blackQueen[i] - blackQueen[k - 1];
			if (flag == 0 || fabs(k - 1 - i) == fabs(flag))
			{
				return 0;
			}
		}
		if (k == n)
		{
			count++;
			return 0;
		}
		for (int i = 0; i < n; i++)
		{
			if (i != whiteQueen[k] && chessBoard[k][i])
			{
				blackQueen[k] = i;
				placeBlackQueen(k + 1);
			}
		}
	}
	
	int placeWhiteQueen (int k)
	{
		for (int i = 0; i < k - 1; i++)
		{
			int flag = whiteQueen[i] - whiteQueen[k - 1];
			if (flag == 0 || fabs(k - 1 - i) == fabs(flag))
			{
				return 0;
			}
		}
		if (k == n)
		{
			placeBlackQueen(0);
			return 0;
		}
		for (int i = 0; i < n; i++)
		{
			if (chessBoard[k][i])
			{
				whiteQueen[k] = i;
				placeWhiteQueen(k + 1);
			}
		}
	}
	
};

int main()
{
	Game game;
	
	game.init(); 
	game.placeWhiteQueen(0);
	cout << game.count;
	
	return 0;
}

FBI树

NOIP全国联赛普及组-2004年NOIP全国联赛普及组

我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。

FBI树是一种二叉树(如下图),它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:

  1. T的根结点为R,其类型与串S的类型相同;

  2. 若串S的长度大于1,将串S从中间分开,分为等长的左右子串S1和S2;由左子串S1构造R的左子树T1,由右子串S2构造R的右子树T2。

现在给定一个长度为2N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历序列。

输入

每组输入数据的第一行是一个整数N(0<=N<=10),第二行是一个长度为2N的“01”串。
数据规模:
对于40%的数据,N<=2;
对于全部的数据,N<=10。

输出

每组输出包括一行,这一行只包含一个字符串,即FBI树的后序遍历序列。

样例输入

3
10001011

样例输出

IBFBBBFIBFIIIFF

代码
#include "iostream"
#include "cstring"
#include "algorithm"

using namespace std;

struct node{
	char data;
	node *left, *right;
};

class FBI_Tree{
public:
	
	int n;	
	string str;
	node *head;
	
	void build (node *tree, int begin, int end)
	{
		bool flagZero, flagOne;
		
		flagZero = flagOne = false;
		for (int i = begin; i <= end; i++)
		{
			if (str[i] == '0')
			{
				flagZero = true;	
			}
			else
			{
				flagOne = true;
			}
		}
		if (flagZero && !flagOne)
		{
			tree->data = 'B';
		}
		if (!flagZero && flagOne)
		{
			tree->data = 'I';
		}
		if (flagZero && flagOne)
		{
			tree->data = 'F';
		}
		if (begin < end)
		{
			tree->left = new node;
			tree->right = new node;
			int mid = (begin + end) / 2;
			build(tree->left, begin, mid);
			build(tree->right, mid + 1, end); 
		}
		else
		{
			tree->left = NULL;
			tree->right = NULL;
			return;
		}
	}
	
	void postOrder(node *tree)
	{
		if (tree)
		{
			postOrder(tree->left);
			postOrder(tree->right);
			cout << tree->data;
			return; 
		}
	}
};



int main()
{
	FBI_Tree fbi_tree;
	
	cin >> fbi_tree.n >> fbi_tree.str;
	fbi_tree.head = new node;
	fbi_tree.build(fbi_tree.head, 0, fbi_tree.str.size() - 1);
	fbi_tree.postOrder(fbi_tree.head);
	
	return 0;
}

矩阵乘法

源地址

有n个矩阵,大小分别为a0a1, a1a2, a2a3, …, a[n-1]a[n],现要将它们依次相乘,只能使用结合率,求最少需要多少次运算。
两个大小分别为p
q和q
r的矩阵相乘时的运算次数计为pqr。

输入

输入的第一行包含一个整数n,表示矩阵的个数。
第二行包含n+1个数,表示给定的矩阵。

输出

输出一个整数,表示最少的运算次数。

样例输入

3
1 10 5 20

样例输出

150

代码
#include "iostream"
#include "algorithm"
using namespace std;

long long dp(long long *a, int n)
{
	long long m[n][n];

	for (int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
        	m[i][j] = 1e15;
		}
        m[i][i] = 0;
    }
	// 连乘的矩阵位置差
	for(int len = 1; len < n; len++)
	{
		for(int i = 0; i < n - len; i++)
		{
			int j = i + len;
			for(int k = i; k < j; k++)
			{
				long long t = m[i][k] + m[k + 1][j] + a[i] * a[k + 1] * a[j + 1];

				if(t < m[i][j])
				{
					m[i][j]=t;	
				}
			}
		}
	}
	return m[0][n - 1];
}

int main()
{ 
	long long a[1001];
	int n;

	cin >> n;
	for (int i = 0; i <= n; i++)
	{
		cin >> a[i];
	}
	cout << dp(a, n);
	
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

该睡觉了zZ

请你一杯咖啡☕

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值