翻硬币
输入
两行等长的字符串,分别表示初始状态和要达到的目标状态。每行的长度<1000
输出
一个整数,表示最小操作步数
样例输入
样例输出
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树的过程如下:
- 找到{pi}中最小的两个数,设为pa和pb,将pa和pb从{pi}中删除掉,然后将它们的和加入到{pi}中。这个过程的费用记为pa+ pb。
- 重复步骤1,直到{pi}中只剩下一个数。
在上面的操作过程中,把所有的费用相加,就得到了构造Huffman树的总费用。
本题任务:对于给定的一个数列,现在请你求出用该数列构造Huffman树的总费用。
例如,对于数列{pi}={5, 3, 8, 2, 9},Huffman树的构造过程如下:
-
找到{5, 3, 8, 2, 9}中最小的两个数,分别是2和3,从{pi}中删除它们并将和5加入,得到{5, 8, 9, 5},费用为5。
-
找到{5, 8, 9, 5}中最小的两个数,分别是5和5,从{pi}中删除它们并将和10加入,得到{8, 9, 10},费用为10。
-
找到{8, 9, 10}中最小的两个数,分别是8和9,从{pi}中删除它们并将和17加入,得到{10, 17},费用为17。
-
找到{10, 17}中最小的两个数,分别是10和17,从{pi}中删除它们并将和27加入,得到{27},费用为27。
-
现在,数列中只剩下一个数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,递归的构造方法如下:
-
T的根结点为R,其类型与串S的类型相同;
-
若串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],现要将它们依次相乘,只能使用结合率,求最少需要多少次运算。
两个大小分别为pq和qr的矩阵相乘时的运算次数计为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;
}