算法基础的学习——郭炜(未完成)


注:本文代码为 C语言 和 C++ 结合

一、枚举

1.完美立方

#include<stdio.h>
int main() {
	int N,a,b,c,d;
	scanf("%d",&N);
	for(a=2; a<=N; a++)
		for(b=2; b<a; b++)
			for(c=b; c<a; c++)
				for(d=c; d<a; d++)
					if(a*a*a==b*b*b+c*c*c+d*d*d)
						printf("Cube = %2d, Triple = (%d,%d,%d)\n",a,b,c,d);
	return 0;
}

2.生理周期

#include<iostream>
#include<cstdio>
using namespace std;
#define N 21252
int main() {
	int p,e,i,d,caseNo=0;
	while(cin>>p>>e>>i>>d && p!=-1) {
		caseNo++;
		int k;
		for(k=d+1; (k-p)%23; k++);
		for(; (k-e)%28; k+=23);
		for(; (k-i)%33; k+=23*28);
		cout<<"Case"<<caseNo<<" : the next triple peak occurs in "<<k-d<<" day"<<endl;
	}
	return 0;
}

3.称硬币

补充:C++中bool函数的学习

//C++中bool函数的返回值是 true or false
#include<iostream>
using namespace std;
bool cmp(int a,int b){
	if(a>b) return true;
	return false;
}
int main(){
	int a,b;
	cin>>a>>b;
	if(cmp(a,b)) cout<<"a > b"<<endl;//若返回值为 true,则执行该if语句
	else cout<<"a < b"<<endl;
	return 0;
}

称硬币 代码如下:

#include<iostream>
#include<cstring>
using namespace std;
char Left[3][7];
char Right[3][7];
char result[3][7];
bool IsFake(char c,bool light);
//light为真->假设假币为轻
//		 假->假设假币为重 
int main() {
	int t,i;
	char c;
	cin>>t;
	while(t--) {
		for(i=0; i<3; i++) cin>>Left[i]>>Right[i]>>result[i];
			//开始枚举: 
			for(c='A'; c<='L'; c++) {
				if(IsFake(c,true)) {
					cout<<c<<" is the counterfeit coin and it is light.";
					break;
				} else if(IsFake(c,false)) {
					cout<<c<<" is the counterfeit coin and it is heavy.";
					break;
				}
			}
	}
	return 0;
}
bool IsFake(char c,bool light) {
	for(int i=0; i<3; i++) {
		char *pLeft,*pRight;
		if(light) {
			pLeft=Left[i];
			pRight=Right[i];
		} else {
			pLeft=Right[i];
			pRight=Left[i];
		}
		switch(result[i][0]) {//天平右边的情况 
			case'u': //此时c应该在右边
				if(strchr(pRight,c) == NULL) 
					return false;
				break;
			case'e': //此时c不应该出现在两边 
				if(strchr(pRight,c) || strchr(pLeft,c))
					return false;
				break;
			case 'd': //此时c应该出现在左边
				if(strchr(pLeft,c) == NULL) 
					return false;
				break;
		}
	}
	return true;
}

输入样例:

1
ABCD EFGH even
ABCI EFJK up
ABIJ EFGH even

输出:

K is the counterfeit coin and it is light.

4.熄灯问题

考虑“局部”

在这里插入代码片

二、递归

作用:
(1)替代多重循环
(2)解决本来就是用递归形式定会的问题
(3)将问题分解为更小的子问题进行求解

1.求n的阶乘

#include<stdio.h>
int Fact(int n){
	if(n==0) return 1;
	return n*Fact(n-1);
}
int main(){
	int n;
	scanf("%d",&n);
	printf("%d",Fact(n));
	return 0;
}

2.汉诺塔问题

#include<stdio.h>
void Hanoi(int n,char a,char b,char c){
	if(n==1){
		printf("%c -> %c\n",a,c);
		return ;
	}
	Hanoi(n-1,a,c,b);
	printf("%c -> %c\n",a,c);
	Hanoi(n-1,b,a,c);
	return ;
}
int Hanoi_step(int m){
	if(m<=1) return 1;
	return 2*Hanoi_step(m-1)+1;
}
int main(){
	int n,count=0;
	scanf("%d",&n);
	Hanoi(n,'A','B','C');
	count=Hanoi_step(n);
	printf("需要移动 %d 次\n",count);
	return 0;
} 

3.N皇后问题

#include<stdio.h>
#include<math.h>
int N;
int queenPos[100];
//用来存放算好的皇后位置。最左上角是(0,0)
void NQueen(int k);
int main() {
	scanf("%d",&N);
	NQueen(0);
	return 0;
}
void NQueen(int k) {
	int i;
	if(k==N) { //N个皇后都摆好了
		for(i=0; i<N; i++)
			printf("%d ",queenPos[i]+1);
		printf("\n");	
		return ;
	}
	for(i=0; i<N; i++) { //逐个尝试第k个皇后的位置
		int j;
		for(j=0; j<k; j++) {
			//和已经摆好的k个皇后比较,看是否冲突
			if(queenPos[j]==i	//看两个皇后的列是不是相同
			        || abs(queenPos[j]-i) == abs(k-j))	//看两个皇后是不是在同一对角线
				break; //冲突,测试下一个位置 
		}
		if(k==j) { //当前选的位置 i 不冲突
			queenPos[k]=i; //姜第k个皇后摆放在i上
			NQueen(k+1);
		}
	}
}

4.逆波兰表达式

atof() 函数是C++的库函数,能将字符串转换成浮点类型的数字。

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
double exp() {
	char s[100];
	cin>>s;
	switch(s[0]) {
		case '+' :
			return exp() + exp();
		case '-' :
			return exp() - exp();
		case '*' :
			return exp() * exp();
		case '/' :
			return exp() / exp();
		default :
			return atof(s);
			break;
	}
}

int main() {
	printf("%lf",exp());
	return 0;
}

5.表达式计算

补充:cin.peek() 和 cin.get() 的使用
cin.peek():看一个字符,不取走
cin.get():从输入中取走该字符

#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
int factor();  //读入一个因子,并返回其值
int term();  //读入一项,并返回其值
int expression();  //读入一个表达式,并返回其值
int main() {
	cout<<expression()<<endl;
	return 0;
}
int factor() {
	int result=0;
	char c=cin.peek();
	if( c == '(' ) {
		cin.get();
		result=expression();
		cin.get();
	} else {
		while(isdigit(c)) {  //如果是数字
			result=10*result + c-'0';  //从高位开始读取,然后累加
			cin.get();
			c=cin.peek();  //不知道有几位数字,继续读取
		}
	}
	return result;
}
int term() {
	int result=factor();  //求第一个因子的值
	while(true) {
		char op=cin.peek();
		if( op == '*' || op == '/' ) {
			cin.get();
			int value=factor();
			if( op == '*' ) result*=value;
			else result/=value;
		} else break;
	}
	return result;
}
int expression() {
	int result=term();   //求第一项的值
	bool more=true;
	while(more) {
		char op=cin.peek();  //看一个字符,不取走
		if( op == '+' || op == '-' ) {
			cin.get(); //从输入中取走该字符
			int value=term();
			if( op == '+' ) result+=value;
			else result-=value;
		} else more=false;
	}
	return result;
}

6.爬楼梯

涉及斐波那契数列

C语言 代码:

#include<stdio.h>
int F(int n){
	if( n == 1 )  return 1;
	if( n == 2 )  return 2;
	return F(n-1) + F(n-2);
} 
int main(){
	int n;
	while( (scanf("%d",&n)) != EOF ){
		printf("%d\n",F(n));
	}
	return 0;
}

C++ 代码:

#include<iostream>
using namespace std;
int F(int n){
	if( n == 1 )  return 1;
	if( n == 2 )  return 2;
	return F(n-1) + F(n-2);
}
int main(){
	int n;
	while( cin>>n ){
		cout<<F(n)<<endl;
	}
	return 0;
}

7.放苹果

#include<stdio.h>
int f(int i,int k){
	if(i<k) return f(i,i);
	if(i==0) return 1;
	if(k==0) return 0;
	return f(i,k-1)+f(i-k,k);
} 
int main(){
	int n,i,j,k;
	scanf("%d",&n);
	for(i=0;i<n;i++){
		scanf("%d %d",&j,&k);
		printf("%d",f(j,k));
	}
	return 0;
}

8.算24

#include<iostream>
#include<cmath>
using namespace std;
#define eps 1e-6
double a[5];
bool isZero(double x) {
	return fabs(x)<=eps;
}
bool count24(double a[],int n) {
	if(n==1) {
		if(isZero(a[0] - 24)) return true;
		else return false;
	}
	double b[5];
	for(int i=0; i<n-1; i++)
		for(int j=i+1; j<n; j++) {
			int m=0; //还剩下 m 个数,m = n-2
			for(int k=0; k<n; k++)
				if(k!=i && k!=j) b[m++]=a[k]; //把其余的数放入b[]
			//加
			b[m]=a[i]+a[j];
			if(count24(b,m+1)) return true;
			//减  注意两种情况
			b[m]=a[i]-a[j]; 
			if(count24(b,m+1)) return true;
			b[m]=a[j]-a[i];
			if(count24(b,m+1)) return true;
			//乘
			b[m]=a[i]*a[j];
			if(count24(b,m+1)) return true;
			//除  注意两种情况
			if(!isZero(a[j])) {
				b[m]=a[i]/a[j];
				if(count24(b,m+1)) return true;
			}
			if(!isZero(a[i])) {
				b[m]=a[j]/a[i];
				if(count24(b,m+1)) return true;
			}
		}
	return false;
}
int main() {
	while(1) {
		for(int i=0; i<4; i++)
			cin>>a[i];
		if(isZero(a[0])) break;
		if(count24(a,4)) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

三、二分算法

1.时间复杂度

时间复杂度的详解

2.二分查找函数

<1>.BinarySearch

#include<stdio.h>
int BinarySearch(int a[],int size,int p) {
	int L=0;
	int R=size-1;
	while(L<=R) {
		int mid = L + (R-L)/2;
		if(p==a[mid]) return mid;
		else if(p>a[mid]) L=mid+1;
		else R=mid-1;
	}
	return -1;
}
int main(){
	int size,p;
	scanf("%d %d",&size,&p);
	int a[size];
	for(int i=0;i<size;i++){
		scanf("%d",&a[i]);
	}
	printf("%d",BinarySearch(a,size,p)+1);  //下标从 1 开始算
	return 0;
}

<2>.LowerBound

#include<stdio.h>
int LowerBound(int a[],int size,int p) {
	int L=0;
	int R=size-1;
	int lastPos=-1;  //到目前为止找到的最优解
	while(L<=R) {
		int mid= L + (R-L)/2;
		if(a[mid]>=p)
			R=mid-1;
		else {
			lastPos=mid;
			L=mid+1;
		}
	}
	return lastPos;
}
int main(){
	int size,p;
	scanf("%d %d",&size,&p);
	int a[size];
	for(int i=0;i<size;i++){
		scanf("%d",&a[i]);
	}
	printf("%d",LowerBound(a,size,p)+1);  //下标从 1 开始算
	return 0;
}

3.二分法求方程的根

#include<stdio.h>
#include<math.h>
#define eps 1e-6
double f(double x) { //定义待求函数
	return x*x*x-5*x*x+10*x-80;
}
//先经过简单求导运算,求出根的大致范围为[0,100]
int main() {
	double root=0,x1=0,x2=100,y=0;
	int count=1;  //计算求根的次数
	root=x1+(x2-x1)/2;
	y=f(root);
	while(fabs(y)>eps) {
		if(y>0) x2=root;
		else x1=root;
		root=x1+(x2-x1)/2;
		y=f(root);
		count++;
	}
	printf("%.8lf\n",root);
	printf("%d",count);
	return 0;
}

4.例题

<1>.寻找指定和的整数对

二分法求解(解法二):

#include<iostream>
#include<algorithm>
using namespace std;
int Find(int a[],int size,int p) {
	int L=0,R=size-1;
	while(L<=R) {
		int mid=L+(R-L)/2;
		if(p==a[mid]) return mid;
		else if(p>a[mid]) L=mid+1;
		else R=mid-1;
	}
	return -1;
}
int main() {
	int i,n,m,flag=0,p=0,r=0;
	cin>>n>>m;
	int a[n];
	for(i=0; i<n; i++)
		cin>>a[i];
	sort(a,a+n);
	for(i=0; i<n/2; i++) {
		p=m-a[i];
		if(Find(a,n,p)>0) {
			r=Find(a,n,p);
			cout<<a[i]<<" "<<a[r]<<endl;
			flag=1;
		}
	}
	if(flag==0) cout<<"No Answer!"<<endl;
	return 0;
}

非二分法求解(解法三):

#include<iostream>
#include<algorithm>
using namespace std;
int main() {
	int n,m;
	cin>>n>>m;
	int a[100000];
	for(int i=0; i<n; i++)
		cin>>a[i];
	sort(a,a+n);
	int i=0,j=n-1;
	while(i<j){
		if(m==a[i]+a[j]){
			cout<<a[i]<<" "<<a[j]<<endl;
			break;
		}
		else if(a[i]+a[j]>m) j--;
		else i++;
	}
	if(i==j) cout<<"No Answer!"<<endl;
	return 0;
}

输入样例:

10 20
2 5 1 11 8 22 20 18 19 27

输出样例 :

2 18

<2>.Agressive cows

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MaxD 1000000000
int N, C;
bool isRight(int d, int pos[]) {
	int cnt=1, pre=pos[0] ; //cnt计数放好位置的牛 初始时第一头牛放在第一个位置
	for(int i=1; i<N; i++) { //for循环开始放置第二头牛(index=1)
		if(pos[i]>=pre+d) {
			pre=pos[i];  //放在第i个位置 更新计数
			cnt++;
		}
		if(cnt==C) return true; //所给的牛都按照距离d放入牛舍了
	}
	return false;
}
int main() {
	int left, right, d, max;
	cin>>N>>C; 
	int pos[N];
	for(int i=0; i<N; i++)
		cin>>pos[i];
	sort(pos,pos+N);//对牛舍序号排序
	left=0;
	right=MaxD/C;
	while(left<=right) {     //二分遍历所有可能的距离,区间为[0,1000000000/c]
		d=(left+right)/2;
		if(isRight(d,pos)) {
			max=d;
			left=d+1;
		} else
			right=d-1;
	}
	cout<<max;
	return 0;
}

输入样例:

5 3
1
2
8
4
9

输出样例:

3

四、分治

1.基本概念

将整个问题分解成若干小问题后再分而治之。如果分解得到的子问题相对来说还是太大,则可反复使用分治策略将这些子问题分成更小的同类型子问题,直至产生方便求解的子问题,必要时逐步合并这些子问题的解,从而得到问题的解。
分治算法可以由递归过程来表示,因为分治法就是一种找大规模问题与小规模问题关系的方法,是递归设计的一种具体策略。

2.归并排序

#include<iostream>
using namespace std;
void Merge(int a[],int s,int m,int e,int b[]) {
//将数组a[s,m]和a[m+1,e]合并到b,并保证b有序,然后再拷贝回a[s,m]
	int pb=0,p1=s,p2=m+1;
	while(p1<=m &&p2<=e) {
		if(a[p1]<a[p2])
			b[pb++]=a[p1++];
		else  b[pb++]=a[p2++];
	}
	while(p1<=m) b[pb++]=a[p1++];
	while(p2<=e) b[pb++]=a[p2++];
	for(int i=0; i<e-s+1; i++)
		a[s+i]=b[i];
}
void MSort(int a[],int s,int e,int b[]) {
	if(s<e) {
		int m=s+(e-s)/2;
		MSort(a,s,m,b);
		MSort(a,m+1,e,b);
		Merge(a,s,m,e,b);
	}
}
int main() {
	int i,size,a[10000],b[10000];
	cin>>size;
	for(i=0; i<size; i++)
		cin>>a[i];
	MSort(a,0,size-1,b);
	for(i=0; i<size; i++)
		cout<<a[i]<<" ";
	cout<<endl;
	return 0;
}

3.快速排序

#include<iostream>
using namespace std;
void swap(int *a,int *b) { 
	int tmp=*a;
	*a=*b;
	*b=tmp;
}
void QuickSort(int a[],int s,int e) {
	if(s>=e) return ;  //递归返回的出口
	int k=a[s];
	int i=s,j=e;
	while(i!=j) {
		while(j>i && a[j]>=k)
			j--;
		swap(&a[i],&a[j]);  //当 a[j]<k 时,交换 a[i] 和 a[j] , 换完 a[j]=k
		while(i<j && a[i]<=k)
			i++;
		swap(&a[i],&a[j]);  //当 a[i]>k 时,交换 a[i] 和 a[j]
	}//处理完后a[i]=k
	QuickSort(a,s,i-1);
	QuickSort(a,i+1,e);
}
int main() {
	int i,size;
	cin>>size;
	int a[size];
	for(i=0; i<size; i++)
		cin>>a[i];
	QuickSort(a,0,size-1);
	for(i=0; i<size; i++)
		cout<<a[i]<<" ";
	cout<<endl;
	return 0;
}

输入样例:

10
93 27 30 2 8 12 2 8 30 89

输出样例:

2 2 8 8 12 27 30 30 89 93

4.例题

<1>.输出前m大的数

#include<iostream>
#include<algorithm>
using namespace std;
void Quick(int a[],int l, int r, int m) {  //快速排序
	if(l>=r) return ;  //递归返回的出口
	int k=a[l];
	int i=l,j=r;
	while(i!=j) {
		while(j>i && a[j]>=k)
			j--;
		swap(a[i],a[j]);
		while(i<j && a[i]<=k)
			i++;
		swap(a[i],a[j]);
	}
	Quick(a,i+1,r,m);  //将 k 右边的数都排序
	if((r-j)<m) Quick(a,l,i-1,m);  //如果 k 右边的数小于 m ,将 k 左边的数也排序
}
int main() {
	int n,m,i;
	cin>>n;
	int a[n];
	for(i=0; i<n; i++)
		cin>>a[i];
	cin>>m;
	Quick(a,0,n-1,m);
	for(i=n-1; i>=(n-m); i--) {
		cout<<a[i]<<endl;
	}
	return 0;
}

输入样例:

10
4 5 6 9 8 7 1 2 3 0
6

输出样例:

9
8
7
6
5
4

<2>.求排列的逆序数

#include<iostream>
#include<algorithm>
using namespace std;
void Merge(int a[],int l,int mid,int r,int b[]) {
	//将左半边和右半边分别按从大到小排序 (归并排序) 
	int pb=0,p1=l,p2=mid+1;
	while(p1<=mid && p2<=r) {
		if(a[p1]>=a[p2])
			b[pb++]=a[p1++];
		else
			b[pb++]=a[p2++];
	}
	while(p1<=mid)
		b[pb++]=a[p1++];
	while(p2<=r)
		b[pb++]=a[p2++];
	for(int i=0; i<r-l+1; i++)
		a[l+i]=b[i];
}
int MSortCount(int a[],int l,int r,int b[]) {
	//计算逆序数有几对 
	int cnt=0;
	if(l<r) {
		int mid=l+(r-l)/2;
		cnt+=MSortCount(a,l,mid,b);    //左半边有的逆序数对
		cnt+=MSortCount(a,mid+1,r,b);  //右半边有的逆序数对
		//计算 两边各取一个数构成的逆序数对:
		int i=l,j=mid+1;
		while(i<=mid && j<=r) {
			if(a[i]<=a[j])
				j++;
			else {
				cnt+=r-j+1;
				i++;
			}
		}
		Merge(a,l,mid,r,b);
	}
	return cnt;
}
int main() {
	int n,i;
	cin>>n;
	int a[n],b[10000];
	for(i=0; i<n; i++)
		cin>>a[i];
	cout<<MSortCount(a,0,n-1,b)<<endl;
	return 0;
}

输入样例:

6
2 6 3 4 5 1
8

五.动态规划

1.数字三角形

法一 : 递归实现

#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX];
int n;
int maxSum[MAX][MAX];
int MaxSum(int i,int j) {
	if(maxSum[i][j]!=-1)
		return maxSum[i][j];  //避免重复计算 
	if(i==n)
		maxSum[i][j]=D[i][j];  //在最后一行,直接返回 D[i][j] 
	else {    //用递归实现 从 底部 向上寻找最大和 
		int x=MaxSum(i+1,j);
		int y=MaxSum(i+1,j+1);
		maxSum[i][j]=max(x,y) + D[i][j];  
	}
	return maxSum[i][j];
}
int main() {
	int i,j;
	cin>>n;
	for(i=1; i<=n; i++)
		for(j=1; j<=i; j++) {
			cin>>D[i][j];
			maxSum[i][j]=-1;  //先赋值 -1 ,用于避免重复计算 
		}
	cout<<MaxSum(1,1)<<endl;
	return 0;
}

法二 : 递推实现(空间优化)

#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX];
int n;
int * maxSum;
int main() {
	int i,j;
	cin>>n;
	for(i=1; i<=n; i++)
		for(j=1; j<=i; j++)
			cin>>D[i][j];
	maxSum=D[n];  // maxSum 指向第 n 行
	for(i=n-1; i>=1; i--)
		for(j=1; j<=i; j++)
			maxSum[j]=max(maxSum[j],maxSum[j+1]) + D[i][j];
	cout<<maxSum[1]<<endl;
	return 0;
}

输入样例:

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

输出样例:

30

2.最长上升子序列

补充:
max_element() 用于从范围 [first, last) 中获取最大值的元素。
min_element() 用于从范围 [first, last) 中获取最小值的元素。

两个函数的用法:

#include <iostream>
#include <algorithm>
using namespace std;
int main() {
	int ans = 0;
	int arr[] = { 1, 2, 3, 4, 2 };

	ans= *max_element(arr + 0, arr + 5);
	cout << "max element of the array:" << ans<< endl;

	ans= *min_element(arr + 0, arr + 5);
	cout << "min element of the array:" << ans<< endl;
	return 0;
}

例题代码:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN=1010;
int a[MAXN];
int maxLen[MAXN];
int main() {
	int n,i,j;
	cin>>n;
	for(i=1; i<=n; i++) {
		cin>>a[i];
		maxLen[i]=1;
	}
	for(i=2; i<=n; i++) //上升子序列的 "终点"(最右边)
		for(j=1; j<i; j++) //遍历"终点"左边的数
			if(a[i]>a[j])
				maxLen[i]=max(maxLen[i],maxLen[j]+1);
	cout<<*max_element(maxLen+1,maxLen+1+n);
	return 0;
}

输入样例:

7
1 7 3 5 9 4 8

输出样例:

4

3.最长公共子序列

#include<iostream>
#include<cstring>
using namespace std;
char s1[1000],s2[1000];
int MaxLen[1000][1000];  //用二维数组来存储公共子序列的长度 
int main() {
	while(cin>>s1>>s2) {
		int len1=strlen(s1);
		int len2=strlen(s2);
		int i,j;
		for(i=0; i<=len1; i++)
			MaxLen[i][0]=0;  //先将长度初始为 0 
		for(j=0; j<=len2; j++)
			MaxLen[0][j]=0;
		for(i=1; i<=len1; i++)
			for(j=1; j<=len2; j++)
				if(s1[i-1]==s2[j-1])  //字符串数组下标从 0 开始算
					MaxLen[i][j]=MaxLen[i-1][j-1]+1;
				else
					MaxLen[i][j]=max(MaxLen[i][j-1],MaxLen[i-1][j]);
					
		cout<<MaxLen[len1][len2]<<endl;
	}
	return 0;
}

输入、输出样例:

abcfbc abfcab
4
programming contest
2
abcd mnp
0

4.最佳加法表达式

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值