算法设计与分析 实验二 分治法

1.汉诺塔:现在给你一个n片圆盘的汉诺塔,并从小到大编号为1

n。请你输出搬动n个圆盘最少次数的全过程。

入:n   出:输出搬动圆盘最少次数的全过程,格式见案例。

入:3   出:Move disk 1 from A to C 。。。。。。Move disk 1 from A to C

#include<iostream> 
#include<string>
#include<cstring> 
#include<cmath>
using namespace std;
void hanoi(int n,char a,char b,char c)
{
	if(n==1)
	{
		cout<<"Move disk "<<"1"<<" from "<<a<<" to "<<c<<endl;
	}
	else{
		hanoi(n-1,a,c,b);
		cout<<"Move disk "<<n<<" from "<<a<<" to "<<c<<endl;
		hanoi(n-1,b,a,c); }}
int main(){
	int n;
	while(scanf("%d",&n)!=EOF){ hanoi(n,'A','B','C'); }
	return 0;
}

2.逆序对:对于一个序列a,如果有ai>aj且i<j,则称ai,aj为一逆序对。

现给定一个序列,求出序列中逆序对的数量(序列中可能存在重复数字)

入:第一行是一个整数,表示序列的长度 n。第二行有 n 个整数,第 i 个整数表示序列的第 i 个数字ai 。

出:输出一个整数

入:6   5 4 2 6 3 1  出:11

#include<iostream 
#include<cstring> 
#include<string> 
#include<cmath>
using namespace std;
int count = 0;
void paixu(int *a, int left, int mid,int right,int *temp) {
	for(int i = left; i <= right; i++) {
		temp[i] = a[i];
	}
	int i = left;
	int j = mid + 1;
	for(int k = left; k <= right; k++) {
		if(i == mid + 1) {
			a[k] = temp[j];
			j++;
		} else if (j == right+1) {
			a[k] = temp[i];
			i++;
		} else if(temp[i] <= temp[j]) {
			a[k] = temp[i];
			i++;
		} else {
			a[k] = temp[j];
			j++;
			count += mid - i + 1;
		}
	}
}
void hanshu(int *a,int left, int right, int *temp) {
	if(left == right) {
		return ;
	}
	int mid = left+(right-left)/2;
	hanshu(a, left, mid,temp);
	hanshu(a, mid+1,right,temp);
	paixu(a,left,mid,right,temp);
}
int main() {
	int n;
	cin>>n;
	int *a=new int[n];
	int *temp=new int[n];
	for(int i = 0 ; i < n; i++) {
		cin>>a[i];
	}
	hanshu(a,0,n-1,temp); printf("%d\n",count);
	return 0;
}

3.数组第K大:给出 n 个数,以及 k ,求数组中的第 k 大的数。

入:一个测试文件内有多组数据,每组数据 n+行,第一行正整数 n, k,接下来 n 个正整数 ai

出:对每组数据输出第 k 大的数

入:5 2     1 3 5 7 9   出:7

#include<iostream> 
#include<algorithm>
using namespace std;
int a[100009];
int cmp(int x,int y){
	return x>y;}
int main(){
	int n,k;
	while(cin>>n>>k){
		for(int i=0;i<n;i++){
			cin>>a[i];
		}
		sort(a,a+n,cmp);
		cout<<a[k-1]<<endl;
	}
	return 0;
}

4.幂运算:给你三个整数a,b,p,求ab mod p的值

入:第一行是一个整数t,表示t组数据。接下来的n行,每行有 3 个整数,分别表示a,b,p

出:每组数据,输出一个整数表示答案。

入:2   2 10 9     2 3 3    出:7    2

#include<iostream> 
#include<string> 
#include<cstring> 
#include<cmath>
using namespace std;
int t; long long b, p, k;
int main() {
	cin>>t;
	for(int i=0; i<t; i++) {
		cin >> b >> p >> k;
		int a = b;
		int c = p;
		int ans = 1;
		while(p > 0) {
			if(p & 1){
				ans = ans * b % k;
			} 
			b = b * b % k;
			p >>= 1;
		}
		cout<<ans%k<<endl;
	}
	return 0;
}

5:斐波那系数列第n项:斐波那契数列即 1, 1, 2, 3, 5...F(n)=F(n1)+F(n2) 。求斐波那契数列第 n 项

出:斐波那契数列第 n 项 对 109+7 取模

入:1    2    20     100000000    出:1    1    6765    908460138

#include<iostream> 
#include<string> 
#include<cstring> 
#include<cmath>
using namespace std;
#define mod(a, m) ((a) % (m) + (m)) % (m)
const int MOD=1e9+7;
struct list {
	long long a[2][2]; }; list a;
long long f[2];
void change(list a) {
	f[0] = mod(a.a[0][0] + a.a[1][0], MOD);
	f[1] = mod(a.a[0][1] + a.a[1][1], MOD);
	return ;
}
list change2(list a, list b) {
	list ans;
	int k;
	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < 2; j++) {
			ans.a[i][j] = 0;
			k = 0;
			while (k < 2) {
				ans.a[i][j] += a.a[k][i] * b.a[j][k];
				ans.a[i][j] = mod(ans.a[i][j], MOD);
				++k;
			}
		}
	}
	return ans;
}
list pow(list a, long long n) {
	list ans;
	ans.a[0][0] = 1; ans.a[1][1] = 1; ans.a[0][1] = 0; ans.a[1][0] = 0;
	while (n) {
		if (n & 1) {
			ans = change2(ans, a);
		}
		n = n >> 1;
		a = change2(a, a);
	}
	return ans;
}
int main() {
	long long n;
	for(int i=0; i<4; i++) {
		while (cin >> n) {
			if (n == 1) {
				cout << '1' << endl;
				continue;
			}
			a.a[0][0] = a.a[0][1] = a.a[1][0] = 1;
			a.a[1][1] = 0;
			a = pow(a, n - 2);
			change(a);
			cout << f[0] <<endl;
		}
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

stearm210

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值