1. 程式人生 > >程式設計菜雞的程式設計之路

程式設計菜雞的程式設計之路

雖然沒有選C2這門課程,不過還是去聽下課順便完成作業吧,反正這學期課挺少的。

小題就算了不寫了。

子串逆置

【問題描述】
輸入兩行字串s和t(s和t可以含空格,length(t)≤length(s)≤50),將s串中首次與t匹配的子串逆置,並將處理後的s串輸出。
【輸入形式】
輸入檔案為當前目錄下的invertsub.in。 檔案中有兩行字串s和t,分別以換行符作為結束符,其中換行符可能是Linux下的換行符,也可能是Windows下的換行符。
【輸出形式】
輸出檔案為當前目錄下的invertsub.out。 輸出檔案只有一行,包含一個串,為要求的輸出結果。行末要輸出一個回車符。
【輸入樣例】
helloworld 
llowor
【輸出樣例】
herowollld
【時間限制】
1s
【空間限制】
65536KB
【上傳檔案】
上傳c語言源程式,檔名為invertsub.c。

在本地測試的時候文字最後沒加換行debug了好久= =,逆置還是挺基礎和簡單的。不過這題用到strstr返回的是出現的地址,所以用指標寫。

#include<stdio.h>
#include<string.h>

void rev(char *first, char *last)
{
	int temp;
	while (first < last)
	{
		temp = *first;
		*first = *last;
		*last = temp;
		first++; last--;
	}
}

int main()
{
	char s[52], t[52], *p;

	FILE *in, *out;
	in = fopen("invertsub.in", "r");
	out = fopen("invertsub.out", "w");

	fgets(s, 52, in); fgets(t, 52, in);
	s[strlen(s) - 1] = '\0';
	t[strlen(t) - 1] = '\0';

	if ((p = strstr(s, t)) != NULL)
		rev(p, p + strlen(t) - 1);

	fprintf(out, "%s\n", s);
	fclose(in); fclose(out);
}

區間

【問題描述】
給定n個閉區間[ai, bi](1 <= i <= n),這些區間的並可以表示為一些不相交的閉區間的並。要求在這些表示方式中找出包含不相交區間數目最少的方案。
【輸入形式】
輸入檔案為當前目錄下的prz.in。 該檔案包含n行(3 <= n <= 50000),每行各包括兩個以空格分隔的整數ai 和 bi,表示一個區間[ai, bi](1 <= ai <= bi <= 1000000)。
【輸出形式】
輸出檔案為當前目錄下的prz.out。 該檔案內容為計算出來的不相交的區間。每一行都是對一個區間的描述,包括兩個以空格分開的整數,分別為區間的下界和上界。 輸出時將各區間按照升序排列輸出。這裡說兩個區間[a, b]和[c, d]是按照升序排列的,是指a <= b < c <= d。
【輸入樣例】
5 6 1 4 10 10 6 9 8 10
【輸出樣例】
1 4 5 10
【時間限制】
1s
【空間限制】
65536KB
【上傳檔案】
上傳c語言源程式,檔名為prz.c。

這次裡面算是最難的一道了吧。分析步驟如下:

(1)首先根據區間的下界排序,這裡如果用複雜度O(n^{2})的排序(我用的選擇排序)好像會超時,所以用快排吧(我這是手寫的快排,用自帶的qsort應該會比較快)

(2)逐個比對,如果區間能夠相交則合併,記錄最大的上界。如果一個區間的下界比之前區間的上界還大,說明這兩個區間必定不相交,輸出之前的區間。

#include<stdio.h>

struct prz {
	int high;
	int low;
}p[50007];

void qsort(struct prz p[], int left, int right);
void print(struct prz p[], int n, FILE *out);
void swap(struct prz p[], int i, int j);

int main() 
{
	FILE *in, *out;
	in = fopen("prz.in", "r");
	out = fopen("prz.out", "w");

	int i;
	int cnt = 0;

	while ((fscanf(in, "%d%d", &p[cnt].low, &p[cnt].high)) != EOF)
	{
		cnt++;
	}

	qsort(p, 0, cnt - 1);
	print(p, cnt, out);

	fclose(in); fclose(out);
}


void qsort(struct prz p[], int left, int right)
{
	struct prz temp;
	int i, j;

	if (left < right) {
		j = left;
		for (i = left + 1; i <= right; i++) {
			if (p[i].low < p[left].low)
				swap(p, i, ++j);
		}
		swap(p, j, left);
		qsort(p, left, j - 1);
		qsort(p, j + 1, right);
	}
}

void print(struct prz p[], int n, FILE *out) 
{
	int last = 0;	
	int i;	
	fprintf(out, "%d ", p[0].low);

	for (i = 1; i < n; i++) 
	{
		if (p[i].low > p[last].high)
		{
			fprintf(out, "%d\n%d ", p[last].high, p[i].low);
			last = i;
		}
		else if (p[i].high > p[last].high)
			last = i;
	}

	fprintf(out, "%d\n", p[last].high);
}

void swap(struct prz p[], int i, int j)
{
	struct prz temp = p[i];
	p[i] = p[j];
	p[j] = temp;
}

兌換硬幣

【問題描述】
寫一個程式,從標準輸入上讀入一個正整數N(1 <= N <=1000),計算出N元人民幣兌換成1分、2分和5分的硬幣,有多少種可能的組合。將結果以整數的方式輸出到標準輸出上,佔一行。
【輸入形式】
正整數N。(1 <= N <=1000)
【輸出形式】
整數。
【輸入樣例】
1
【輸出樣例】
541
【時間限制】
1s
【空間限制】
65536KB
【上傳檔案】
上傳c語言源程式,檔名為nickle.c。

水題。暴力做會超時。

事實上如果遍歷5分硬幣的數量,根據剩餘金額可以直接算出來有幾種組合,因為只需要數2分硬幣有幾種情況,剩下的1分都能補足。我稍微化簡了一下所以看著不是很清晰,湊合吧。

#include<stdio.h>

int count(int n)
{
	int i;
	int cnt = 0;

	for (i = 0; i <= n * 20; i++)
	{
		cnt += (n * 100 - i * 5) / 2 + 1;
	}

	return cnt;
}

int main()
{
	int n;
	scanf("%d", &n);
	printf("%d", count(n));
}

實數格式識別

【問題描述】
合法的實數書寫格式分一般格式和科學格式兩種。分別描述如下:
一般格式為常見的書寫格式,分為整數部分和小數部分兩部分,中間分用小數點.分隔。整數部分最開始可能含有正號或負號,之後為不含前導零的數字串;小數部分是由0-9十種字元組成的任意長的字串。當小數部分為0時,小數部分和小數點可以省略。
科學格式由係數部分和指數部分兩部分組成,中間用英文字母E分隔。係數部分為實數書寫的一般格式;指數部分為可帶有正負號數字串。
例如,+2、-1.56為一般格式的實數,而6.2E-2、-9E8為科學格式的實數。
只有小數點而沒有小數部分的書寫格式為不合法,例如,23.,23.E16均為不合法的實數書寫格式。
程式設計分析哪些數的書寫是正確的,是用哪種方式書寫的。
【輸入形式】
輸入檔案為當前目錄下的real.in。 該檔案包含一個字串(長度不超過20個字元),以回車符結束,表示一個數據(無多餘空格)。
【輸出形式】
輸出檔案為當前目錄下的real.out。 該檔案有一行。如果輸入資料的書寫是非法的,輸出Wrong;如果輸入資料是用一般格式書寫的,輸出“Format1”;如果該資料是用科學格式書寫的,輸出“Format2”。輸出的末尾均要以一個回車符作為結束。
【輸入樣例1】
+1.23
【輸出樣例1】
Format1
【輸入樣例2】
-5.1.1
【輸出樣例2】
Wrong
【輸入樣例3】
-5.1E-2
【輸出樣例3】
Format2
【時間限制】
1s
【空間限制】
65536KB
【上傳檔案】
上傳c語言源程式,檔名為real.c。

不難但是很繁瑣的一道題,思路可以用狀態機來完成,但是我怕出錯就沒這麼寫。一開始寫了一個超級繁瑣的版本後來改成下面這個版本。

普通格式與科學格式的特徵區別:E <普通格式> E [<符號>] <整數>

如果有E我們就用科學格式來判別,E前面是否為<普通格式>,後面是否為[符號]+整數。如果沒有E我們就判斷是否為普通格式。

普通格式的兩種型別:是否有小數點 [<符號>]<整數> . <整數> [<符號>]<整數>

所以我們根據有無小數點,判斷小數點前面和後面是否分別滿足條件即可。

#include<stdio.h>
#include<string.h>
#include<stdbool.h>
#include<ctype.h>

void judge(char s[], int length, FILE *out);
bool judgeDec(char s[], int first, int last);
bool judgeInt(char s[], int first, int last);
bool judgeExp(char s[], int fisrt, int last, int eindex);

int main()
{
	char s[22];

	FILE *in, *out;
	in = fopen("real.in", "r");
	out = fopen("real.out", "w");

	fgets(s, 22, in);
	s[strlen(s) - 1] = '\0';
	int length = strlen(s);

	judge(s, length, out);

	close(in); close(out);
	return 0;
}

void judge(char s[], int length, FILE *out)
{
	int i;
	 
	for (i = 0; i < length; i++)
		if (s[i] == 'E')
			break;

	if (i + 1 == length)
		fprintf(out, "Wrong\n");
	else if (i == length)
	{
		if (judgeDec(s, 0, length - 1))
			fprintf(out, "Format1\n");
		else
			fprintf(out, "Wrong\n");
	}
	else
	{
		if (judgeExp(s, 0, length - 1, i))
			fprintf(out, "Format2\n");
		else
			fprintf(out, "Wrong\n");
	}
}

bool judgeDec(char s[], int first, int last)
{
	int pindex;
	int pflag = 0;
	bool judge = false;
	int i = (s[first] == '-' || s[first] == '+') ? first + 1 : first;

	for (pindex = first; pindex <= last; pindex++)
		if (s[pindex] == '.')
		{
			pflag++;
			break;
		}

	if (!pflag)
		judge = judgeInt(s, i, last);
	else
		judge = judgeInt(s, i, pindex - 1) && judgeInt(s, pindex + 1, last);

	return judge;
}

bool judgeInt(char s[], int first, int last)
{
	if (first > last)
		return false;

	while (isdigit(s[first]) && first <= last)
		first++;

	if (first == last + 1)
		return true;
	else
		return false;
}

bool judgeExp(char s[], int first, int last, int eindex)
{
	bool judge = false;
	int i = (s[eindex + 1] == '-' || s[eindex + 1] == '+') ? eindex + 2 : eindex + 1;
	judge = judgeDec(s, first, eindex - 1) && judgeInt(s, i, last);
	return judge;
}

在judgeDec和judgeExp我沒有對left<=right進行規約, 因為呼叫時已經滿足了這個條件。  

N!的分解

【問題描述】
將N!分解成素數冪的乘積。
【輸入形式】
從標準輸入讀取一個整數N(1 <= N <= 30000)。
【輸出形式】
結果列印到標準輸出。 輸出格式為:p1^k1*p2^k2…其中p1,p2…為質數且ki>1。當ki=1時只輸出pi,ki=0的項不輸出。分解式中的素數按從小到大輸出。
【輸入樣例】
5
【輸出樣例】
2^3*3*5
【時間限制】
1s
【空間限制】
65536KB
【上傳檔案】
上傳c語言源程式,檔名為decompose.c。

對2~N出現的每一個數,將其所有質因子加入質數表中記錄出現次數。不過我沒有記錄用質數表而是直接用陣列存,反正效果差不多= =

另外輸出的時候特判一下就行了

#include<stdio.h>
#define MAXNUM 30001
int prime[MAXNUM] = { 0 };

void gen_factor(int n, int prime[]);
void print(int n, int prime[]);

int main()
{
	int n;
	scanf("%d", &n);
	gen_factor(n, prime);
	print(n, prime);
}

void gen_factor(int n, int prime[])
{
	int i, j, temp;
	for (i = 2; i <= n; i++)
	{
		temp = i;
		for (j = 2; j <= temp; j++)
		{
			if (temp % j == 0)
			{
				prime[j] ++;
				temp /= j;
				j--;
			}
		}
	}
}

void print(int n, int prime[])
{
	int i, first = 1;
	for (i = 2; i <= n; i++)
	{
		if (prime[i] == 1)
		{
			if (first)
			{
				first = 0;
				printf("%d", i);
			}
			else
				printf("*%d", i);
		}
		else if (prime[i] > 1)
		{
			if (first)
			{
				first = 0;
				printf("%d^%d", i, prime[i]);
			}
			else
				printf("*%d^%d", i, prime[i]);
		}
	}
}

好好學吧,這學期儘量堅持一件事。把C2的平時練習都寫完然後寫部落格,看看能不能堅持這學期