题目:
A–三值排序
排序是一种很频繁的计算任务。一个实际的例子是,当我们给某项竞赛的优胜者按金银铜牌排序的时候。在这个任务中可能的值只有三种1,2和3。我们用交换的方法把他排成升序的。
写一个程序计算出,计算出的一个包括1、2、3三种值的数字序列,排成升序所需的最少交换次数。
输入第1行为类别的数量N(1≤N≤1000)
输入第2行到第N+1行,每行包括一个数字(1或2或3)。
输出包含一行,为排成升序所需的最少交换次数。
Sample Input
9
2
2
1
3
3
3
2
3
1
Sample Output
4
思路:
首先分析,无论交换前的数据如何,交换后一定可以分为三部分,第一部分是数据“1”,第二部分是数据“2”,第三部分是数据“3”,由于“1”永远在最前面,所以我门可以先固定第一部分,然后讨论第二、三部分
(1)首先找出数据中 “1”的个数sum1,即完成第一部分排序需要的步数
(2)然后要做的就只有 将第二部分中的“3”交换到第三部分、或者将第三部分的“2”交换到第二部分,分别记为sum2和sum3
(3)取sum1+max(sum2,sum3),至于为什么要取sum2和sum3之间的最大值,是因为如果取最小值,那么必定会有“2”遗留在第三部分或者“3”遗留在第二部分,取决于两者到底谁小
思路写出来挺繁琐的但不难理解,直接上代码:
#include <stdio.h>
#include <string.h>
int a[1001], cnt[4];
int main(void)
{
int n, i;
scanf("%d",&n);
for(i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
cnt[a[i]]++;
}
int sum1 = 0, sum2 = 0, sum3 = 0;
for(i = 1; i <= cnt[1]; i++)
{
if(a[i] != 1)
sum1++;
}
for(i = cnt[1] + 1; i <= cnt[1] + cnt[2]; i++)
{
if(a[i] == 3)
sum2++;
}
for(i = cnt[1] + cnt[2] + 1; i <= n; i++)
{
if(a[i] == 2)
sum3++;
}
printf("%d\n", sum1 + (sum2 > sum3 ? sum2 : sum3));
return 0;
}
B–自然数拆分
对于任意大于 1的自然数 n,总是可以拆分成若干个小于 n的自然数之和。
现请你编写程序求出 n 的所有拆分。
输入格式:
输入文件共一行,包含一个自然数,即要拆分的自然数 n(1≤n≤20)。
输出格式:
输出文件有若干行,每行包含一个等式,即代表一种可行的拆分(格式与顺序参见样例)。
Sample Input
5
Sample Output
5=1+1+1+1+1
5=1+1+1+2
5=1+1+3
5=1+2+2
5=1+4
5=2+3
思路:待补全
代码:
#include<stdio.h>
int n;
int a[25];
void dfs(int sum,int len,int start)
{
if(n==sum)
{
printf("%d=%d",n,a[0]);
for(int i=1;i<len;i++)
{
printf("+%d",a[i]);
}
printf("\n");
return ;
}
for(int i=1;i<n;i++)
{
if(sum+i<=n && i>=start)
{
a[len++]=i;
dfs(sum+i,len,i);
len--;
}
}
}
int main(void)
{
scanf("%d",&n);
dfs(0,0,1);
return 0;
}