天天看點

3.數組和字元串

3.數組和字元串

數組

  1. 逆序輸出
    #include<stdio.h>
    #define maxn 1000000
    int a[maxn];
    
    int main()
    {
      	int x, n=0;
        // 輸入
    	while(scanf("%d", &x) == 1)
    		a[n++] = x;
        // 輸出 
    	for(int i=n-1; i>=1; i--){
    		printf("%d ", a[i]);
      	}
    	printf("%d\n", a[0]);
    	return 0;	
    }
    
               
    1. a[n++]

      ,首先指派

      a[n]=x

      ,然後執行

      n=n+1

    2. 對于變量n,n++和++n都會給n加1,但當它們用在一個表達式中時,行為有所差别:n++會使用加1的值計算表達式,而++n會使用加1後的值計算表達式
    3. 比較大的數組盡量聲明在main函數外,否則程式可能無法運作
  2. 開燈問題

    n盞燈,第1個人把所有燈打開,第2個人按下所有編号為2的倍數的開關(這些燈将被關掉),第3個人按下所有編号為3的倍數的開關(其中關掉的燈将被打開,開着的燈将被關掉),依此類推。一共有k個人,問最後有哪些燈開着?

    輸入n和k,輸出開着的燈的編号。k<=n<=1000。

    #include<stdio.h>
    #include<string.h>
    #define maxn 1010
    int a[maxn];
    
    int main()
    {
        int n, k, first = 1;
        // 數組a初始化為0 
        memset(a, 0, sizeof(a));
        scanf("%d%d", &n, &k);
        // 模拟讓每個人去按開關 
        for(int i=1; i<=k; i++){
    	    for(int j=1; j<=n; j++){
    		    if(j%i == 0){
    			    a[j] = !a[j];
    		    }
    	    }
        }
        // 輸出 
        for(int i=1; i<=n; i++){
    	    if(a[i]){
    		    // 輸出時第一個數字前無空格 
    		    if(first){
    			    first = 0;
    		    }else{
    			    printf(" ");
    		    }
    		    printf("%d", i);
    	    }
        }
        printf("\n");	
        return 0;	
    }
               

    memset(a, 0, sizeof(a));

    的作用是把數組初始化為0,定義在string.h中。
  3. 蛇形填數

    在nn方陣裡填入1,2,…,nn,要求填成蛇形。n<=8。

    #include<stdio.h>
    #include<string.h>
    #define maxn 20
    #define maxm 20
    int a[maxn][maxm];
    
    int main()
    {
        int n, x=0, y=0, tot = 0; 
        scanf("%d", &n);
        memset(a, 0, sizeof(a));
        tot = a[0][y=n-1] = 1;
        // 指派過程 
        while(tot < n*n)
        {	
    	    // 先向下走 
    	    while(x+1<n && !a[x+1][y])
    	    {
    		    a[++x][y] = ++tot;
    	    }
    	    // 向左走 
    	    while(y-1>=0 && !a[x][y-1])
    	    {
    		    a[x][--y] = ++tot;
    	    }
    	    // 向上走 
    	    while(x-1>=0 && !a[x-1][y])
    	    {
    		    a[--x][y] = ++tot;
    	    }
    	    // 向右走 
    	    while(y+1<n && !a[x][y+1])
    	    {
    		    a[x][++y] = ++tot;
    	    }
        }
        // 輸出 
        for(x=0; x<n; x++)
        {
    	    for(y=0; y<n; y++)
    		    printf("%3d", a[x][y]);
    	    printf("\n");
        }
    
        return 0;	
    }
               
    這道題的思路值得好好思考。

字元數組

  1. 豎式問題
    #include<stdio.h>
    #include<string.h>
    
    int main()
    {
        int count = 0;
        char s[20], buf[99];
        scanf("%s", s);
        for(int abc=111; abc<=999; abc++)
        {
    	        for(int de=11; de<=99; de++)
    	        {
    		    int x = abc*(de%10), y = abc*(de/10), z = abc*de;
    		    sprintf(buf, "%d%d%d%d%d", abc, de, x, y, z);
    		    // 檢查每個字元是否都在輸入的集合
    		    int ok = 1;
    		    for(int i=0; i<strlen(buf); i++)
    		    {
    			    if(strchr(s, buf[i]) == NULL)
    				    ok = 0;
    		    } 
    		    if(ok)
    		    {
    			    printf("<%d>\n", ++count);
    			    printf("%5d\nX%4d\n-----\n%5d\n%4d\n-----\n%5d\n\n", abc, de, x, y, z);
    		    }
    	    }
    	
        }
        printf("The number of solutions = %d\n", count);
        return 0;
     }
               
    模拟豎式計算,但是必須豎式中所有的字元都必須屬于輸入的數字集合。
  2. 趣測試
    #include<stdio.h>
    #include<math.h>
    
    int main()
    {
        int count = 0;
        printf("%d %d %d", count++, count++, count++);
        return 0;
    }
               
3.數組和字元串
#include<stdio.h>

    int main()
    {
	    int count = 0;
	    count = count++;
	    printf("%d", count);
	    return 0;
    }
           
3.數組和字元串

競賽題目選講

  1. Tex中的引号
    #include<stdio.h>
    
    int main()
    {
        int c, q=1;
        while((c = getchar()) != EOF)
        {
    	    if(c == '"')
    	    {
    		    printf("%s", q ? "``":"''");
    		    q = !q;
    	    }else{
    		    printf("%c", c);
    	    }
        }
        return 0;
    }
               
    getchar,讀取下一個字元。
  2. WERTUYU

    輸入一個錯位後敲出的字元串,輸出打字員本來想打出的句子。輸入保證合法。

    #include<stdio.h> 
    char s[] = "`1234567890-=QWERTYUIOP[]\\ASDFGHJKL;'ZXCVBNM,./";
    
    int main()
    {
        int i,c;
        while((c = getchar()) != EOF)
        {
    	    for(i=1; s[i] && s[i] != c; i++);
    	    if(s[i]){
    		    putchar(s[i-1]);	
    	    }else{
    		    putchar(c);
    	    }
        }
        return 0;
    }
               
  3. 回文詞

    輸入一個字元串,判斷它是否為回文串以及鏡像串。輸入字元串保證不含數字0。所謂回文串,就是反轉以後和原串相同,如abba和madam。所有鏡像串,就是左右·鏡像之後和原串相同,如2S和3AIAE。注意,并不是每個字元在鏡像之後都能得到一個合法字元。

    #include<stdio.h>
    #include<string.h>
    #include<ctype.h>
    // 每個字元的鏡像字元 A-Z 1-9 
    const char* rev = "A   3  HIL JM o   2TUVWXY51SE Z  8 ";
    // 輸出的結果 “不是回文串” “回文串” “鏡像串” “鏡像回文串” 
    const char* msg[] = {"not a palindrome", "a regular palindrome", "a mirrored string", "a mirrored palindrome"};
    
    char r(char ch) {
        // isalpha 判斷字元是否為字母  
        if(isalpha(ch)) {
    	    return rev[ch - 'A'];
        }
        return rev[ch - '0' + 25]; 
    }
    
    int main() {
        char s[30];
        while(scanf("%s", s) == 1) {
    	    // 字元串長度 
    	    int len = strlen(s);
    	    //  标志 
    	    int p = 1, m = 1;
    	    for(int i=0; i<(len+1)/2; i++) {
    		    //  是否是回文串 
    		    if(s[i] != s[len-1-i]) {
    			    p = 0;
    		    }
    		    // 是否是鏡像串 
    		    if(r(s[i]) != s[len-1-i]) {
    			    m = 0;
    		    }
    	    }
    	    printf("%s -- is %s.\n\n", s, msg[m*2+p]);
        }
        return 0;
    }
               
  4. 猜數字遊戲的提示

    實作一個經典“猜數字”遊戲。給定答案序列和使用者猜的序列,統計有多少數字位置正确(A),有多少數字在兩個序列都出現過但位置不對(B)。

    #include<stdio.h>
    #define maxn 1010
    
    int main() {
        int n, a[maxn], b[maxn];
        int kase = 0;
        while(scanf("%d", &n) == 1 && n) {
    	    printf("Game %d:\n", ++kase);
    	    // 輸入答案序列 
    	    for(int i =0 ; i<n; i++) {
    		    scanf("%d", &a[i]);
    	    }
    	    // 處理猜測序列 
    	    for(;;) {
    		    int A = 0, B = 0;
    		    // 求出位置正确的數字個數A 
    		    for(int i=0; i<n; i++) {
    			    scanf("%d", &b[i]);
    			    if(a[i] == b[i]) A++;
    		    }
    		    // 當猜測序列全為0退出 
    		    int sign = 1;
    		    for(int i=0; i<n; i++){
    			    if(b[i] != 0){
    				    sign = 0;
    				    break;
    			    } 
    		    }
    		    if(sign == 1) break;
    		    // 找到兩個序列都出現過的數字個數B 
    		    for(int d=1; d<=9; d++) {
    			    int c1 = 0, c2 = 0;
    			    for(int i = 0; i<n; i++) {
    				    if(a[i] == d) c1++;
    				    if(b[i] == d) c2++;
    			    }
    			    if(c1<c2) B += c1;
    			    else B += c2;
    		    }
    		    // 輸出結果 
    		    printf("    (%d, %d)\n", A, B-A);
    	    }
        }
        return 0;
    }  
               
    這裡做了一個小實驗,
    #include<stdio.h>
    #include<math.h>
    
    int main()
    {
        int count = 0;
        printf("%d \n", ++count);
        printf("%d \n", count);
        return 0;
    }
               
    3.數組和字元串
    再看下面這個程式運作結果,
    #include<stdio.h>
    #include<math.h>
    
    int main()
    {
        int count = 0;
        printf("%d \n", count++);
        printf("%d \n", count);
        return 0;
    }
               
    3.數組和字元串
  5. 生成元

    如果x加上x的各個數字之和得到y,就說x是y的生成元。給出n(1<=n<=100000),

    求最小生成元。無解輸出0。例如,n=216, 121,2005時的解分别為198,0,1979。

    // 一次性枚舉
    #include<stdio.h>
    #include<string.h>
    #define maxn 100005
    int ans[maxn];
    
    int main() {
        int T, n;
        memset(ans, 0, sizeof(ans));
        for(int m=1; m < maxn; m++){
    	    int x = m, y = m;
    	    // 把x的每一位與x加起來 
    	    while(x > 0){
    		    y += x % 10;
    		    x /= 10;
    	    } 
    	    // 把最小的生成元儲存下來 
    	    if(ans[y] == 0 || m < ans[y]){
    	    	ans[y] = m;
    	    }
        }
        scanf("%d", &T);
        while(T--){
    	    scanf("%d", &n);
    	    printf("%d\n", ans[n]);
        }
        return 0;
    }
               
  6. 環狀序列

    長度為n的環狀串有n種表示法,分别為從某個位置開始順時針得到。在這些表示法中,字典序最小的稱為“最小表示”。

    輸入一個長度為n(n<=100)的環狀DNA串(隻包含A、C、G、T這4種字元)的額、一種表示法,你的任務是輸出該環狀串的最小表示。

    #include<stdio.h>
    #include<string.h>
    #define maxn 105
    
    // 比較分别以p和q為開頭的序列 
    int less(const char* s, int p, int q){
        int n = strlen(s);
        for(int i= 0; i < n; i++){
    	    if(s[(p+i)%n] != s[(q+i)%n]){
    		    return s[(p+i)%n] < s[(q+i)%n];
    	    }
        }
        return 0; 
    } 
    
    int main(){
        int T;
        char s[maxn];
        // T個字元串 
        scanf("%d", &T);
        // 擷取輸入、處理字元串 
        while(T--){
    	    scanf("%s", s);
    	    // 到目前為止的标志 
    	    int ans = 0; 
    	    // 字元串的長度 
    	    int n = strlen(s);
    	    // 找到最小的字元 
    	    for(int i=1; i<n; i++){
    		    if(less(s, i, ans)) ans = i;
    	    }
    	    // 輸出最小表示 
    	    for(int i=0; i< n; i++){
    		    putchar(s[(i+ans)%n]);
    	    }
    	    putchar('\n');
        }
        return 0;
    }
               

練習

  1. 得分

    給出一個由O和X組成的串(長度為1~80),統計得分。每個O的得分為目前連續出現的O的個數,X的得分為0。

    #include<stdio.h>
    #include<string.h>
    char s[82];
    
    int main() {
        int score=0;
        int sign1=0; 
        scanf("%s", s);
        int strength = strlen(s);
        for(int i=0; i<strlen(s); i++){
    	    if(s[i] == 'O'){
    		    sign1++;
    	    }else{
    		    sign1 = 0;
    	    } 
    	    score += sign1;
        }
        printf("%d", score);
        return 0;
    }
               
  2. 分子量

    給出一種物質的分子式(不帶括号),求分子量。本題中的分子式隻包含4種原子,分别為C、H、O、N,原子量分别為12.01,1.008,16.00,14.01(機關:g/mol)。例如,C6H5OH的分子量為94.108g/mol。

    #include<stdio.h>
    #include<ctype.h>
    #include<string.h>
    char s[100];
    
    // 每個字母對應的數值 
    double getNum(char r){
        double a = 0.0;
        if(r == 'C'){
    	    a = 12.01;
        }
        if(r == 'H'){
    	    a = 1.008;
        }
        if(r == 'O'){
    	    a = 16.00;
        }
        if(r == 'N'){
    	    a = 14.01;
        }
        return a;
    }
    
    int main(){
        scanf("%s", s);
        double all =0;
        // 循環周遊 
        for(int i=0; i< strlen(s); i++){
    	    // 如果是一個字母 
    	    if(isalpha(s[i])){
    		    // 如果不是最後一個字元
    		    if(i+1 < strlen(s)){
    			    // 如果下一個是數字 
    			    if(!isalpha(s[i+1])){
    				    // 那麼相乘 
    				    all += getNum(s[i])*(int)(s[i+1]-'0');
    				    continue;
    			    }else{
    				    // 不是數字就不用乘 
    				    all += getNum(s[i]);
    				    continue;
    			    }
    		    }else{
    			    // 加上最後一個字元 
    			    all += getNum(s[i]);
    			    continue;
    		    }
    		
    	    }
        }
        printf("%f\n", all);
        return 0;
    }
               
    記住:字元數字轉整形數字的方法
  3. 數數字

    把前n(n<=10000)個整數順次寫在一起:123456789101112···數一數0~9各出現多少次,輸出10個整數。

    #include<stdio.h>
    #include<string.h>
    
    int a[10];
    char s[100005];
    
    int main() {
        scanf("%s", s);
        // 初始化數組 
        memset(a, 0, sizeof(a));
        // 獲得輸入串的實際長度 
        int n = strlen(s);
        // 指派a數組 
        for(int i=0; i<n; i++) {
    	    int c = (int)(s[i]-'0');
    	    a[c]++;
        }
        // 輸出數組 
        for(int i=0; i<10; i++) {
    	    printf("%d ",a[i]);
        }
        return 0;
    }
               
  4. 周期串

    如果一個字元串可以由某個長度為k的字元串重複多次得到,則稱該串以k為周期。例如,abcabcabcabc以3為周期(注意,它也以6和12為周期)

    輸入一個長度不超過80的字元串,輸出其最小周期。

  5. 謎題

    一個5*5方格,其中恰好有一個格子是空的,其他格子各有一個字母。一共有4種指令:A、B、L、R,分别表示把空格上、下、左、右的相鄰字母移到空格中。輸入初始網格和指令序列(以數字0結束),輸出指令執行完畢後的網格。如有非法指令,應輸出“This puzzle has no final configuration.”

繼續閱讀