目录
NOJ 2018.9.21
A、二分查找
时限:1000ms 内存限制:10000K 总时限:3000ms | |
描述 | 给定一个单调递增的整数序列,问某个整数是否在序列中。 |
输入 | 第一行为一个整数n,表示序列中整数的个数;第二行为n(n不超过10000)个整数;第三行为一个整数m(m不超过50000),表示查询的个数;接下来m行每行一个整数k。 |
输出 | 每个查询的输出占一行,如果k在序列中,输出Yes,否则输出No。 |
输入样例 | 5 1 3 4 7 11 3 3 6 9 |
输出样例 | Yes No No |
#include <iostream>
using namespace std;
int a[10001];
int n;
int check[50001];
int m;
void getdata(){
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
cin >> m;
for(int i = 0; i < m; i++){
cin >> check[i];
}
}
int search(int c){
int left = 1, right = n;
int mid;
while(left <= right){
mid = (left + right) / 2;
if(a[mid] == c){
return mid;
}
else if(a[mid] > c){
right = mid - 1;
}
else{
left = mid + 1;
}
}
return 0;
}
int main(){
getdata();
for(int i = 0; i < m; i++){
int ret = search(check[i]);
if(ret){
cout << "Yes" << endl;
}
else{
cout << "No" << endl;
}
}
return 0;
}
B、归并排序
时限:1000ms 内存限制:10000K 总时限:3000ms | |
描述 | 给定一个数列,用归并排序算法把它排成升序。 |
输入 | 第一行是一个整数n(n不大于10000),表示要排序的数的个数; |
输出 | 输出排序后的数列,每个数字占一行。 |
输入样例 | 5 3 2 1 4 5 |
输出样例 | 1 2 3 4 5 |
#include <iostream>
using namespace std;
void copy(int left, int right);
void merge(int left, int i, int right);
int n;
int a[10000];
int b[10000];
void mergeSort(int left, int right)
{
if(left < right){
int i = (left + right)/2;
mergeSort(left, i);
mergeSort(i + 1, right);
merge(left, i, right);
copy(left,right);
}
}
void merge(int left, int i, int right)
{
int save_begin = left;
int left_end = i++;
int right_end = right;
while((left <= left_end) && (i <= right_end)){
if(a[left]>a[i])
b[save_begin++] = a[i++];
else
b[save_begin++] = a[left++];
}
if(left <= left_end)
while(left <= left_end)
b[save_begin++] = a[left++];
else
while(i <= right_end)
b[save_begin++] = a[i++];
}
void copy(int left, int right){
while(left <= right){
a[left] = b[left];
left++;
}
}
int main()
{
cin >> n;
for(int i = 0; i < n; i++)
cin >> a[i];
mergeSort(0, n-1);
for(int i = 0; i < n; i++)
cout << a[i] << endl;
return 0;
}
C、快速排序
时限:1000ms 内存限制:10000K 总时限:3000ms | |
描述 | 给定一个数列,用快速排序算法把它排成升序。 |
输入 | 第一是一个整数n(n不大于10000),表示要排序的数的个数;下面一行是用空格隔开的n个整数。 |
输出 | 输出排序后的数列,每个数字占一行。 |
输入样例 | 5 3 2 1 4 5 |
输出样例 | 1 2 3 4 5 |
#include <iostream>
using namespace std;
int a[10005];
int n;
void getdata(){
cin >> n;
for(int i = 0; i < n; i++)
cin >> a[i];
}
void output()
{
for(int i = 0; i < n; i++)
cout << a[i] << endl;
}
int qsort(int left, int right){
int pivotkey = a[left];
while(left < right){
while((left < right) && (a[right] >= pivotkey))right--;
a[left] = a[right];
while((left < right) && (a[left] <= pivotkey))left++;
a[right] = a[left];
}
a[left] = pivotkey;
return left;
}
void quicksort(int left, int right){
if(left < right){
int p = qsort(left, right);
quicksort(left, p - 1);
quicksort(p + 1, right);
}
}
int main(){
getdata();
quicksort(0, n-1);
output();
}
D、走迷宫
时限:1000ms 内存限制:10000K 总时限:3000ms | |
描述 | 判断是否能从迷宫的入口到达出口 |
输入 | 先输入两个不超过20的正整数表示迷宫的行数m和列数n,再输入口和出口的坐标,最后分m行输入迷宫,其中1表示墙,0表示空格每个数字之间都有空格。 |
输出 | 只能向上、下、左、右四个方向走若能到达,则输出”Yes”,否则输出”No”,结果占一行。 |
输入样例 | 3 3 0 0 2 2 0 0 0 1 1 0 0 1 0 |
输出样例 | Yes |
提示:
从起点开始深搜,找到联通的地方置为2,直至深搜结束;查看终点的值是否改变。
#include <iostream>
using namespace std;
int m, n;
int a[20][20];
int b_x, b_y;
int e_x, e_y;
void input(){
cin >> m >> n;
cin >> b_x >> b_y;
cin >> e_x >> e_y;
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
cin >> a[i][j];
}
void output(){
if(a[e_x][e_y] == 2)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
void dfs(int x, int y){
//cout << x << " " << y <<endl;
if((x >= 0) && (y >= 0) && (x < m) && (y < n)){
if(a[x][y])
return;
else{
a[x][y] = 2;
dfs(x,y-1);//shang
dfs(x-1,y);//zuo
dfs(x,y+1);//xia
dfs(x+1,y);//you
}
}
else
return;
}
int main(){
input();
dfs(b_x, b_y);
output();
return 0;
}
E、穷举n位2进制数
时限:100ms 内存限制:10000K 总时限:300ms | |
描述 | 输入一个小于20的正整数n,要求按从小到大的顺序输出所有的n位二进制数,每个数占一行。 |
输入 | 输入一个小于20的正整数n。 |
输出 | 按从小到大的顺序输出所有的n位二进制数,每个数占一行。 |
输入样例 | 3 |
输出样例 | 000 001 010 011 100 101 110 111 |
#include <iostream>
using namespace std;
int n;
char s[20];
void dfs(int m){
if(m==n){
s[m] = 0 ;
cout << s << endl;
}
else{
for(int i = 0; i < 2; i++){
s[m] = i + '0';
dfs(m+1);
}
}
}
int main()
{
cin >> n;
dfs(0);
return 0;
}
F、穷举所有排列
时限:100ms 内存限制:10000K 总时限:300ms | |
描述 | 输入一个小于10的正整数n,按把每个元素都交换到最前面一次的方法,输出前n个小写字母的所有排列。 |
输入 | 输入一个小于10的正整数n。 |
输出 | 按把每个元素都交换到最前面一次的方法,输出前n个小写字母的所有排列。 |
输入样例 | 3 |
输出样例 | abc acb bac bca cba cab |
提示:
基于回溯、分治思想;
把全部元素换到最前面一次,先确定前k层元素,再进入k+1层,依次与剩余所有元素交换(包括自身),交换一次后进入下一层,直至进入第n层递归,此时确定整个序列;
递归返回后,再次还原至原有序列
#include <iostream>
using namespace std;
char a[20];
int n;
void change(int i, int j){
char t = a[i];
a[i] = a[j];
a[j] = t;
}
void dfs(int m){
if(m == n){ //当固定了前n-1个元素,即确定排列的顺序,输出
cout << a << endl;
}
else{
for(int i = m; i < n; i++){ //确定前m-1个位置的元素
change(i, m); //交换下标为i和m位置的元素
dfs(m + 1); //递归下一层
change(i, m); //还原
}
}
}
int main(){
for(int i = 0; i < 10; i++){
a[i] = i + 'a';
}
cin >> n;
a[n]=0; //初始化为字符串,以便输出
dfs(0); //开始排序
return 0;
}
//以下算法是另一种排序
/*
int n;
char a[20];
char s[10];
int used[10];
void init(){
cin >> n;
for(int i = 0; i < 10; i++){
a[i] = i + 'a';
}
}
void dfs(int m){
if(m == n)
{
s[m] = 0;
cout << s << endl;
}
else{
for(int i = 0; i < n; i++){
if(used[i] == 0){
s[m] = a[i];
used[i] = 1;
dfs(m+1);
used[i] = 0;
}
}
}
}
int main(){
init();
dfs(0);
return 0;
}
*/
G、循环赛日程表
时限:1000ms 内存限制:10000K 总时限:3000ms | |
描述 | 用分治算法生成循环赛日程表(1到2的n次方个人) |
输入 | 一个小于等于7的正整数n |
输出 | 循环赛日程表(1到2的n次方个人) |
输入样例 | 3 |
输出样例 | 1 2 3 4 5 6 7 8 |
注意:OJ上最后一个元素输出后没有空格
#include <iostream>
using namespace std;
int n;
int a[129][129];
void copyto(int b_x, int b_y, int m)
{
//cout << b_x << " " << b_y << " " << m << endl;
int e_x = b_x + m;
int e_y = b_y + m;
for(int i = 0; i < m; i++)
for(int j = 0; j < m; j++){
a[b_x + m + i][b_y + m + j] = a[b_x + i][b_y + j];
a[b_x + m + i][b_y + j] = a[b_x + i][b_y + j + m];
}
}
void table(){
int m = 1; //jian ju
int k = 1; //ci shu
for(int i = 1; i <= n; i++) k *= 2;
for(int i = 1; i <= k; i++) a[1][i] = i;
for(int s = 1; s <= n; s++){ // lie shang ci shu
k /= 2; // hang shang ci shu
m *= 2; //jian ju
for(int i = 1; i <= k; i++)
copyto(1, (i - 1) * m + 1, m / 2);
}
}
void output(){
int k = 1;
for(int i = 1; i <= n; i++) k *= 2;
for(int i = 1; i <= k; i++)
{
for(int j = 1; j <= k - 1; j++)
cout << a[i][j] << " ";
cout << a[i][k];
cout << endl;
}
}
int main(){
cin >> n;
table();
output();
return 0;
}
H、求第k小数
时限:1000ms 内存限制:10000K 总时限:3000ms | |
描述 | 求第k小数 |
输入 | 先输入一个小于10000的正整数n,再输入n个整数,最后输入一个小于等于n的正整数k, |
输出 | 输出其中第k小的数。 |
输入样例 | 5 2 98 34512 8492 1000 2 |
输出样例 | 98 |
有点懒,直接使用上面的快排了;
其实可以在每次快排结束后判断枢轴的位置,与k进行比较,从而舍弃对另一部分的排序,而且元素所在部分也并不需要排序(无需对子序列递归),只需确定枢轴所在位置即可;但是这也要记录再上一次快排的结果以便确定所求数的所在范围。
#include <iostream>
using namespace std;
int a[10005];
int n;
int k;
void getdata(){
cin >> n;
for(int i = 0; i < n; i++)
cin >> a[i];
cin >> k;
}
void output()
{
cout << a[k-1] <<endl;
}
int qsort(int left, int right){
int pivotkey = a[left];
while(left < right){
while((left < right) && (a[right] >= pivotkey))right--;
a[left] = a[right];
while((left < right) && (a[left] <= pivotkey))left++;
a[right] = a[left];
}
a[left] = pivotkey;
return left;
}
void quicksort(int left, int right){
if(left < right){
int p = qsort(left, right);
quicksort(left, p - 1);
quicksort(p + 1, right);
}
}
int main(){
getdata();
quicksort(0, n-1);
output();
}