C语言之数学问题

一、全排列

  从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
  交换法:全排序以‘123’为例,全排列就是从第一个数字起每个数分别与它后面的数字交换。i表示递归次数,k表示固定数字位数,后面的数字进行交换。当k等于数组长度时输出,返回递归过程并恢复交换。
全排列递归过程
  代码如下:

#include<stdio.h>
#include<string.h>
void swap(char *a, char *b)
{
	char temp;
	temp = *a;
	*a = *b;
	*b = temp;
}
void fullPermutation(char *str, int k, int len)			// k表示当前固定数字个数
{
	int i;
	if(k == len)
	{
		for(int j = 0; j <= len; j++)
			printf("%c", str[j]);
		printf("\n");
	}
	else
		for(i = k; i <= len; i++)
		{	
		//若数组有元素相同,则定义一个比较函数和此处if控制语句
			swap(str + i, str + k);
			fullPermutation(str, k + 1, len);
			swap(str + i, str + k);
		}
		
}
int main()
{
	char str[10];
	scanf("%s", str);
	fullPermutation(str, 0, strlen(str)-1);
	return 0;
}

  填数法:将输出1到n分解为输出以1、2、3等为开头的全排列,设一个数组array和散列数组hashTable,假设当前已经填好了前index个数字,正准备填下一个数字,需要枚举hashTable数组中未填入的数字。

#include<cstdio>
const int maxn = 11;
int n, P[maxn], hashTable[maxn] = {false};
 
void generateP(int index){
	//边界 
	if(index == n+1){
		for(int i = 1;  i <= n; i++){
			printf("%d", P[i]);
		}
		printf("\n");
		return;
	}
	for(int x = 1; x <= n; x++){
		if(hashTable[x] == false){
			P[index] = x;
			hashTable[x] = true;
			generateP(index+1);
			hashTable[x] = false;
		}
	} 	
} 
 
int main(){
	n = 4;
	generateP(1);
	return 0;
}

二、进制转换

  进制转换是人们利用符号来计数的方法。进制转换由一组数码符号和两个基本因素“基数”与“位权”构成。基数是指进位计数制中所采用的数码(数制中用来表示“量”的符号)的个数。位权是指进位制中每一固定位置对应的单位值。

  • 将p进制数x转换为十进制数y
	int y = 0,product = 1;
	while(x != 0)
	{
		y = y + (x % 10)*product;		//(x%10)获取个位数
		x = x / 10;						//去掉个位数
		product = product * p;
	}
	

 

  • 将十进制数y转换为Q进制数
	int array[111];
	int num = 0;//余数的位数
	do{
		array[num++] = y%q;//除基取余
		y /= q; 
	} while(y != 0) //当商不为0时进行循环
	//注意逆序输出

三、最大公约数与最小公倍数

1.最大公约数

  正整数 a 与 b 的最大公约数是 a 和 b所有公约数中最大的那个公约数,一般用 gcd(a, b) 来表示,常用欧几里得算法。(即辗转相除法)

/* 辗转相除法
a,b均为正整数,gcd(a, b) = gcd(b, a % b)
证明a = kb + r, a % b = (kb + r) % b, a % b = r % b
*/
#include<stdio.h>
int gcd(int a, int b)
{
	if(b == 0)
		return a;
	else
		return gcd(b, a % b);
}
int main()
{
	int a, b;
	while(scanf("%d%d", &a, &b) != EOF)
	{
		printf("%d\n", gcd(a, b));
	}
	return 0;
}

2.最小公倍数

  正整数 a 和 b 的所有公倍数中最小的公倍数。最小公倍数的求解在最大公约数的基础上,即ab/gcd(a, b)。为防止ab在计算中溢出,可以采用a/gcd(a, b)*b。

#include<stdio.h>
int gcd(int a, int b)
{
	if(b == 0)
		return a;
	else
		return gcd(b, a % b);
}
int main()
{
	int a, b;
	while(scanf("%d%d", &a, &b) != EOF)
	{
		printf("%d\n", a/gcd(a, b)*b);
	}
	return 0;
}

四、分数

1.分数的表示

struct Fraction
{//分别为分子、分母
    int up;
    int down;
};

  定义 Fraction 结构体类型表示分数,需要以下规则:

  • 如果分母 down 为负数,那么令分子 up 和分母 down 都变为相反数。
  • 如果分子 up 为 0,那么令分母 down为 1。
  • 约分:求出分子绝对值与分母绝对值的最大公约数 gcd(up, down),然后令分子分母同时除以 gcd(up, down)。
//分数化简
Fraction reduction(Fraction result)
{
    if(result.down < 0)
	{
        result.up = -result.up;
        result.down = -result.down;
    }
    if(result.up == 0)
	{
        result.down = 1;
    }
	else
	{
        int d = gcd(result.up, result.down);
        result.up /= d;
        result.down /= d;
    }
    return result;
}

2.分数的四则运算

//分数加法
Fraction add(Fraction f1, Fraction f2)
{
    Fraction result;
    result.up = f1.up * f2.down + f2.up * f1.down;
    result.down = f1.down * f2.down;
    return reduction(result);
}
//分数减法
Fraction minu(Fraction f1, Fraction f2)
{
    Fraction result;
    result.up = f1.up * f2.down - f2.up * f1.down;
    result.down = f1.down * f2.down;
    return reduction(result);
}
//分数乘法
Fraction multi(Fraction f1, Fraction f2)
{
    Fraction result;
    result.up = f1.up * f2.up;
    result.down = f1.down * f2.down;
    return reduction(result);
}
//分数除法
Fraction divide(Fraction f1, Fraction f2)
{
    Fraction result;
    result.up = f1.up * f2.down;
    result.down = f2.up * f1.down;
    return reduction(result);
}

3.分数输出

  分数输出需遵循以下规则:

  • 输出分数前,需要对其进行化简
  • 如果分数 r 的分母 down为 1,说明该分数是整数。
  • 如果分数 r 的分子 up 的绝对值大于分母 down,说明改分数是假分数,应该以带分数的形式输出,即整数部分为 r.up / r.down,分子部分为 abs(r.up) % r.down,分母部分为 r.down。
#include<stdio.h>
#include<math.h>
 
struct Fraction
{
    int up;
    int down;
};
int gcd(int a, int b)
{
    if(b == 0)
	{
        return a;
    }
    return gcd(b, a%b);
}
//分数化简
Fraction reduction(Fraction result)
{
    if(result.down < 0)
	{
        result.up = -result.up;
        result.down = -result.down;
    }
    if(result.up == 0)
	{
        result.down = 1;
    }
	else
	{
        int d = gcd(result.up, result.down);
        result.up /= d;
        result.down /= d;
    }
    return result;
}
//分数加法
Fraction add(Fraction f1, Fraction f2)
{
    Fraction result;
    result.up = f1.up * f2.down + f2.up * f1.down;
    result.down = f1.down * f2.down;
    return reduction(result);
}
//分数减法
Fraction minu(Fraction f1, Fraction f2)
{
    Fraction result;
    result.up = f1.up * f2.down - f2.up * f1.down;
    result.down = f1.down * f2.down;
    return reduction(result);
}
//分数乘法
Fraction multi(Fraction f1, Fraction f2)
{
    Fraction result;
    result.up = f1.up * f2.up;
    result.down = f1.down * f2.down;
    return reduction(result);
}
//分数除法
Fraction divide(Fraction f1, Fraction f2)
{
    Fraction result;
    result.up = f1.up * f2.down;
    result.down = f2.up * f1.down;
    return reduction(result);
}
//分数输出
void showFraction(Fraction r)
{
    r = reduction(r);
    if(r.down == 1) 
		printf("%d\n", r.up);
    if(abs(r.up) > r.down)
        printf("%d %d/%d\n", r.up/r.down, abs(r.up)%r.down, r.down);
    else
        printf("%d/%d\n", r.up, r.down);
}
 
int main(){
    Fraction f1;
    f1.up = 6;
    f1.down = 4;
	showFraction(f1);
    return 0;
}

五、素数

/*
筛选法原理:如果 n 不是素数,那么 n 一定有小于 n 的素数因子,
那么一定会在枚举到 n 之前被筛选掉。
*/
#include<stdio.h>
const int maxn = 1000001;
int p[maxn] = {0};
int pNum = 0, prime[maxn];
void Find_Prime(int n)
{
    for(int i = 2; i < maxn; i++)
	{
        if(p[i] == false)
		{
            prime[pNum++] = i;
            if(pNum>=n) break;
            for(int j = i*2 ; j < maxn; j += i)
			{
                p[j] = true;
            }
        }
    }
}
int main()
{
	//筛选法输出数组 m 到 n 之间的素数
    int m, n;
    scanf("%d%d", &m, &n);
    Find_Prime(n);
    for(int i = m; i <= n; i++)
        printf("%d\n", prime[i-1]);
    return 0;
}

六、大整数运算

#include<stdio.h>
#include<string.h>
int convert(char str[], int num[])               //将字母转变为数字,按照低位到高位存放
{
	int i, len = strlen(str);
	for(i = 0; i < len; i++)
	{
		num[i] = str[len-i-1] - '0';
	}
	return len;
}
//大整数加法
void add(char *str1, char *str2)
{
	int a[1001] = {0}, b[1001] = {0};			 //数组置0
	int n1, n2, n;
	n1 = convert(str1,a);
	n2 = convert(str2,b);
	n = n1 >= n2?n1:n2;
	int i, flag = 0;							//flag为进位
	for(i = 0; i < n; i++)
	{
		int temp = (a[i] + b[i] + flag)/10;		//商为进位,余数为当前位结果
        a[i] = (a[i] + b[i] + flag)%10;
        flag = temp;
	}
	if(flag)									 //最高位产生进位
		a[n++] = flag;
	for(i = n-1; i >= 0; i--)
        printf("%d", a[i]);
	printf("\n");
}
//大整数减法
void sub(char *str1, char *str2)
{
	int a[1001] = {0}, b[1001] = {0};			 //数组置0
	int n1, n2, n, i, flag = 0;					//flag为进位;
	char *temp;
	if(strlen(str1) < strlen(str2) || (strlen(str1) == strlen(str2) && strcmp(str1, str2) < 0))
	{											//判断大小输出负号
		temp = str1;
		str1 = str2;
		str2 = temp;
		printf("-");
	}
	n1 = convert(str1,a);
	n2 = convert(str2,b);
	n = n1 >= n2?n1:n2;
	if(n1 >= n2)
	{
		n =n1;
	}
	for(i = 0; i < n; i++)
	{
		if(a[i] < b[i])							//借位	
		{
			a[i+1]--;
			a[i] += 10;
		}
		a[i] = a[i] - b[i];
	}
	while(n > 1 && a[n-1] == 0)					//去掉高位的0,同时至少保留一位最低位
	{
		n--;
	}
	for(i = n-1; i >= 0; i--)
        printf("%d", a[i]);
	printf("\n");
}
int main()
{
	char str1[1001], str2[1001];
	while(scanf("%s%s", str1, str2) != EOF)
	{
		
		add(str1, str2);
		sub(str1, str2);		 
	}
	return 0;
}

七、日期差值

  • 题目描述:
   有两个日期,求两个日期之间的天数,如果两个日期是连续的,则规定他们之间的天数为两天。
   每组输出一行,即日期差值
  • 输入&输出:
   20130101
   20130105
   5
  • 代码:
	#include<stdio.h>
	int month[13][2] = {{0,0}, {31,31}, {28,29}, {31,31}, {30,30}, {31,31}, {30,30}, {31,31}, {31,31}, {30,30}, {31,31}, {30,30}, {31,31}
	};
	bool isLeap(int year)
	{ 
		return (year%4 == 0 && year%100 != 0 || year%400 == 0);
	}
	int main()
	{
		int time1, y1, m1, d1;
		int time2, y2, m2, d2;
		while(scanf("%d%d", &time1, &time2) != EOF)
		{
			if(time1 > time2) //第一个日期晚于第二个日期,则交换
			{
			     int temp = time1;
				 time1 = time2;
				 time2 = temp;	
			} 
			y1 = time1/10000,m1 = time1%10000/100, d1 = time1%100;
			y2 = time2/10000,m2 = time2%10000/100, d2 = time2%100;
			int ans = 1; //记录结果
			
			while(y1 < y2 || m1 < m2 || d1 < d2)
			{
				d1++;
				if(d1 == month[m1][isLeap(y1)]+1)  //当月天数+1正好为下一个月1号 
				{
					m1++;   //日期变为下个月1号 
					d1 = 1;
				}
				if(m1 == 13) //月份满12月 
				{
					y1++;   //日期变为下一年的1月 
					m1 = 1;
				}
				ans++;//结果 
			} 
			printf("%d\n", ans+1);        //这里要注意题目,连续的两天,天数为2
		}
			return 0;
	}

八、牛顿迭代法

  牛顿迭代法(Newton’s method)又称为牛顿-拉夫逊(拉弗森)方法(Newton-Raphson method),它是牛顿在17世纪提出的一种在实数域和复数域上近似求解方程的方法。
在这里插入图片描述
  该方法使用函数的泰勒级数的前面几项来寻找方程 的根。牛顿迭代法是求方程根的重要方法之一,几何上就是不断用(x,f(x))的切线来逼近方程。

/*
x^3 - a = 0
立方根公式:x = (2*x + a/x/x)/3;
x^2 - a = 0
平方根公式:x = (x + a/x)/2
*/
#include<stdio.h>
double my_abs (double x)
{
	return x > 0 ? x:-x;
}
double getCube(double y)
{
	double x =  1.0;
	while(my_abs(x*x*x-y)>1e-7)
	{
		x = (2*x + y/x/x)/3;
	}
	return x;
}
int main()
{
	double input;
	scanf("%lf", &input);
	printf("%.1lf\n", getCube(input));
	return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值