2014年12月29日星期一

[UVa] 514 - Rails

卡了很久
因為輸出的 "Yes" 寫成 "YES" ...

Stack基本題
已有通盤的瞭解

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <iostream>
#include <stack>
using namespace std;
int main(){
  freopen("input.txt","r",stdin);
  int n, B[1001];
  int tmp=0;
  while(scanf("%d",&n)==1){
    if(n==0)break;
    while(1){
      memset(B,0,sizeof(B));
      stack<int> s;
      for(int i=0;i<n;i++){
        scanf("%d",&B[i]);
        if(B[i]==0)break;
      }
      if(B[0]==0){
        puts("");
        break;
      }
      int flag=0,A=1,ok=1; 
      while(flag<n){ 
        if(A==B[flag]){
          A++;
          flag++;
        }
        else if(!s.empty() && s.top()==B[flag]){
          flag++;
          s.pop();
        }
        else if(A<n){
         s.push(A);
         A++;
        }else {
          break;
        }
      }
      if(s.empty())printf("Yes");else printf("No");
      puts("");
    }

  }
  return 0;
}

2014年12月23日星期二

[UVa] 101 - The Blocks Problem

參考算法競賽入門經典ㄧ書

運用STL中vector的一些特性

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <cctype>
#include <set>
#include <map>
#include <vector>
#include <sstream>
using namespace std;
int n;
vector<int> pile[30];
void find_block(int a, int& p, int& h){
  for(p=0;p<n;p++){
    for(h=0;h<pile[p].size();h++){
      if(pile[p][h]==a)return; //找到後回傳p及h之位址
    }
  }
}
void clear_above(int p, int h){
  for(int i=h+1; i<pile[p].size();i++){
    int b = pile[p][i];
    pile[b].push_back(b); //put b back
  }
  pile[p].resize(h+1); //改變大小,只保留h以下
}
void pile_onto(int p, int h, int p2){
  for(int i=h; i<pile[p].size(); i++)
    pile[p2].push_back(pile[p][i]); //p堆高度h以上的移到p2
  pile[p].resize(h); //h-1以上的去除
}

int main(){
  scanf("%d",&n);
  int a,b;
  string s1,s2;
  for(int i=0;i<n;i++) pile[i].push_back(i) ; 
  while(cin >> s1){
    if(s1=="quit")break;
    cin >> a >> s2 >> b; 
    int pa,pb,ha,hb;
    find_block(a, pa, ha);
    find_block(b, pb, hb);
    if(pa == pb)continue; //ignore
    if(s2 == "onto")clear_above(pb,hb); //遇onto則b上方木塊全部歸位
    if(s1 == "move")clear_above(pa,ha); //遇move則a上方木塊全部歸位
    pile_onto(pa, ha, pb);
  }
  for(int i=0;i<n;i++){
    printf("%d:", i);
    for(int j=0;j<pile[i].size();j++)printf(" %d", pile[i][j]);
    printf("\n");
  }
  return 0;
}

2014年12月22日星期一

[UVa] 10194 - Football (aka Soccer)

這題卡了挺久的,拿了不少WA

待有空debug完再放上來

沒有完成真的無心往下繼續...

2014年12月14日星期日

[UVa] 123 - Searching Quickly

這次算是STL的實習

運用了一些功能強大的函式

在此作個簡介

set : 集合,不會包含相同元素的集合

map : 可作一對一映射,兩者的資料型態可以不同

multimap : 可作一對多的映射

本題的作法,因為multimap在建立之時,就已經以前者元素作排序

getline讀入的一行也因為先後順序不同,在插入map時也排序好了

所以在map建立後直接輸出即可

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cctype>
#include <set>
#include <map>
using namespace std;
int main(){
  freopen("input.txt", "r", stdin);
  set<string> igwords;
  set<string>::iterator it; 
  string input;
  while(1){ //insert ignore words into igwords set
    cin >> input;
    if(input=="::")break;
    else {
      igwords.insert(input);
      input.erase();
    }
  }
  string title;
  multimap<string,string> titles;
  map<string,string>::iterator it_map =titles.begin();
  while(getline(cin,input)){ //getline(input_stream,destination_string)
    title.erase();
    for(int i=0;i<=input.size();i++)input[i] = tolower(input[i]); 
    for(int i=0;i<=input.size();i++){
      if(!isalpha(input[i])){
        if(igwords.count(title)==0 && isalpha(title[0])){ //如果和igwords都不相符
          string input_tmp = input; //開始將input中的單字轉為大寫存入input_tmp
          int tmp = i - title.length(); //
          for(int k = tmp; k < tmp+title.length(); k++) input_tmp[k]=toupper(input[k]); 
          titles.insert(it_map,pair<string,string>(title,input_tmp)); //存入titles中
        }
        title.erase();
        continue;
      }
      title+=input[i];
    }
    input.erase();
  }
  //print set
//  for(it=igwords.begin();it!=igwords.end();it++)cout << *it << '\n';
//  cout << "\n";
  for(it_map=titles.begin();it_map!=titles.end();it_map++)cout << it_map->second << '\n';
  return 0;

}

2014年12月8日星期一

[UVa] 400 - Unixls

奇怪的是,題目說最右邊欄的寬度是最大檔名長,但輸出時卻都要+2才會過...



/*-----------------------------------------------------*/
/*參考程式競賽與演算法入門經典P.5-32內容               */
/*-----------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int max_col = 60; //最大行數
const int maxn = 105; //檔案名稱最大長度
string filenames[maxn];

int main(){
  freopen("input.txt", "r", stdin);
  int n=0;
  while(cin >> n){
    int M = 0;  //檔案名稱最長長度
    for(int i=0;i<n;i++){
      cin >> filenames[i];
      if((int)filenames[i].length()>M) M = filenames[i].length();
    }
    sort(filenames, filenames+n); //sort
    for(int i=0;i<60;i++)printf("-");
    printf("\n");    
    //行數=最大行數減最大檔名,除上最大檔名加2(得到除最後一行的行數)
    //再把最後一行加回來的數即是
    int cols = (max_col-M)/(M+2) + 1;
    int rows = n/cols; 
    if(n%cols==0); else rows++; //無條件進位

    int flag;
    for(int r=0;r<rows;r++){
      for(int c=0;c<cols;c++){
        flag = c*rows+r; //直接計算出位置
        if(flag < n)cout << filenames[flag];
        for(int i=0; i<M-(int)filenames[flag].length() ;i++)cout << " ";
        cout << "  ";
      }
      cout << "\n"; 
    }
  }


  return 0;
}

2014年12月5日星期五

[UVa] 156 - Ananagrams

要注意的點很多

主要流程:換小寫,字串內排序,比對抽出原字串,原字串互相排序,輸出



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <cstdio>
#include <cstring
#include <iostream>
using namespace std;
int main(){
  //freopen("input.txt", "r", stdin);
  char words[1500][30]; //up to 1000 words and 20 letters.
  char input[30];
  int count=0; //count the number of words
  memset(input,'\0',sizeof(input));
  memset(words,'\0',sizeof(words));

  while(scanf("%s",input)!=EOF){
    if(input[0]=='#'){
        count--;
        break;
    }
    strcpy(words[count],input);
    count++;
    memset(input,'\0',sizeof(input));
  }

  //換小寫
  char words_s[1500][30]={'\0'};
  for(int i=0;i<=count;i++){
    for(int j=0;j<30;j++){
      words_s[i][j]=tolower(words[i][j]);
    }
  }

  //排序
  int flag = 0;
  for(int i=0;i<=count;i++){
    for(int j=0;words_s[i][j]!='\0';j++){
      for(int k=j+1;k<strlen(words[i]);k++){
        if(words_s[i][k]<=words_s[i][j]){ //exchange
          char tmp;
          tmp = words_s[i][k];
          words_s[i][k] = words_s[i][j];
          words_s[i][j] = tmp;
        }
      }
    }
  }    
  //檢查相同
  char words_ok[1500][30];
  int is_ananagram;
  flag=0;
  memset(words_ok,'\0',sizeof(words_ok));
  for(int i=0;i<=count;i++){
    is_ananagram=1;
    for(int j=0;j<=count;j++){
      if(strcmp(words_s[i],words_s[j])==0 && i!=j){
        is_ananagram=0;
        break;
      }
    }
    if(is_ananagram==1 || strlen(words_ok[flag])==1){ //是獨立字或為個別字母
      strcpy(words_ok[flag],words[i]);
      flag++;
    }
  }
  int ok_count = flag; 
  //檢查出來的陣列 words_ok 按照字母排序
  for(int i=0;i<ok_count;i++){
    for(int j=i+1;j<ok_count;j++){
      if(strcmp(words_ok[i],words_ok[j])>0)
      {   char tmp[30];
          strcpy(tmp,words_ok[i]);
          strcpy(words_ok[i],words_ok[j]);
          strcpy(words_ok[j],tmp);
      }
    }
  }


  /*
  for(int i=0;i<=count;i++){
    for(int j=0;words_s[i][j]!='\0';j++)printf("%c",words_s[i][j]);
    printf("\n");
  }
  */

  for(int i=0;i<ok_count;i++){
    //for(int j=0;words_ok[i][j]!='\0';j++)
      printf("%s",words_ok[i]);
    printf("\n");
  }
  return 0;

}

2014年11月24日星期一

[UVa] 120 - Stacks of Flapjacks


 注意輸出的方式,因為是由底下輸出,要注意變數的換算。 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int main(){

  int cakes[50];
  memset(cakes,0,sizeof(cakes));
  char input[1000];
  memset(input,'\0',sizeof(input));

  while(fgets(input,sizeof(input),stdin)!=NULL){ //讀取一整行
    int cake_num = 0; //蛋糕數 初始化
    for(int i=0;i<sizeof(input);i++){ //將input列中的個別數字轉換為整數存入cakes
       if(input[i]>='0' && input[i]<='9'){
         int tmp = input[i]-'0';
         cakes[cake_num] = cakes[cake_num]*10;
         cakes[cake_num] += tmp;
       }
       if(input[i]==' ')cake_num++; //遇到空格,蛋糕數++
    }

    for(int i=0;i<=cake_num;i++)printf("%d ",cakes[i]);
    printf("\n");
 
   
    int n = cake_num; // n為計算還沒處理的cakes,在n以下的cakes都已經完成排序
    while(n){
      int max = 0;
      int max_flag=0; //最大值旗標
      for(int i=0;i<=n;i++){
        if(cakes[i] >= max){ //找出最大值其位置(flag)
          max = cakes[i];
          max_flag = i;
        }
      }
      if(max_flag==n){ //如果最底下的就是最大值,則查找範圍往上縮減
        n--; //縮減
        max = 0;
        max_flag = 0;
      }else if(max_flag==0 || cakes[0]==cakes[max_flag]){ //如果最大值在最上面或最大值和最上面相等,則直接全部翻轉
        int top=0, buttom=n; 
        while(1){
          if(top >= buttom)break;
          int tmp = cakes[top]; //交換Pie
          cakes[top] = cakes[buttom];
          cakes[buttom] = tmp;
          top++; buttom--;
        }
        printf("%d ",cake_num-n+1);
        n--; //最大值已翻轉到最下面,往上縮減範圍
      }else{
        int top=0, buttom=max_flag; //將最大值以上的翻轉
        while(1){
          if(top >= buttom)break;
          int tmp = cakes[top]; //交換Pie
          cakes[top] = cakes[buttom];
          cakes[buttom] = tmp;
          top++; buttom--;
        }
        printf("%d ",cake_num-max_flag+1);
        //n--; //縮減 
      }
   }
   printf("0\n");    
   // for(int i=0;i<=cake_num;i++)printf("%d ",cakes[i]);
   // printf("\n");
    memset(cakes,0,sizeof(cakes));
    memset(input,'\0',sizeof(input));  
  }
   
  return 0;
} 

2014年11月20日星期四

[UVa] 299 - Train Swapping


只能左右交換的排序
以陣列來看,在第 i 個位置,向右找到和自己位置相同的數字
一直向左交換回來即可 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int train[70]; //train carriages
int main(){
  memset(train,0,sizeof(train));
  int n; //cases
  scanf("%d",&n);
  while(n--){
    int L; //length of traiin
    int count=0; //swap count
    scanf("%d",&L);
    for(int i=0;i<L;i++)scanf("%d",&train[i]); 
    for(int i=0;i<L;i++){
      for(int j=i;j<L;j++){
        if(train[i] == i+1)break;
        if(train[j] == i+1){  //左右交換
            int tmp = train[j];
            train[j] = train[j-1];
            train[j-1] = tmp;
            j=i;
            count++;
        }  
      }
    }
    //for(int i=0;i<L;i++)printf("%d ",train[i]);    
    //printf("\n");
    printf("Optimal train swapping takes %d swaps.\n",count);
  }

  return 0;  
} 

[Note] Ubuntu 磁碟清理

這邊引用 Tsung's Blog 的貼文
http://blog.longwin.com.tw/2011/02/linux-free-hd-clean-2011/

  1. 清空 Trash bin
  2. apt-get clean # 清除 local repository 淘汰得 Package (deb)
  3. apt-get autoclean # 清除舊版本的 暫存 Package (deb)
  4. apt-get autoremove # 刪除系統不再使用的 Package
  5. /var/cache/apt/archives # Package (deb) cache
  6. /var/cache/apt/archives/partial # 沒有下載完成的 Package 放在這邊
  7. ~/.mozilla/firefox/*.default/Cache # 若已經指定進 Ram Disk, 就不用管這個.
  8. /var/log/*
  9. /tmp/*

另外還有 Rex's blah blah blah 關於清理儲存空間的貼文

內有詳盡的介紹

2014年11月19日星期三

[UVA] 152 - Tree's a Crowd

運用一個新的函數 pow ,可取回傳入數值的某次方
輸入輸出皆為double
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

//int trees[6000][3]; //6000 trees, 3-dimensional
int x[6000],y[6000],z[6000];
int hist[10];
int main(){
  freopen("input.txt", "r", stdin);
  memset(hist,0,sizeof(hist));
  double input_x, input_y, input_z;
  int t=0;
  while(scanf("%d %d %d", &x[t], &y[t], &z[t])!=EOF){
    if(x[t]==0 && y[t]==0 && z[t]==0)break;
    t++; // next tree
  }  
   
  for(int i=0;i<t;i++){
    double min_d=10000; 
    for(int j=0;j<t;j++){
      if(i==j)continue;
      double d=sqrt(pow(x[i]-x[j],2.0)+pow(y[i]-y[j],2.0)+pow(z[i]-z[j],2.0));
      //sqrt(dx^2+dy^2+dz^2)

      //printf("%.2f\n",d);

      if(d<=min_d){
        min_d = d;
      }
    }
    if(min_d==10000)break;
    //printf("%.2f\n",min_d);
    if(min_d<1 && min_d>=0)hist[0]++;
    else if(min_d>=1 && min_d<2)hist[1]++;
    else if(min_d>=2 && min_d<3)hist[2]++;
    else if(min_d>=3 && min_d<4)hist[3]++;
    else if(min_d>=4 && min_d<5)hist[4]++;
    else if(min_d>=5 && min_d<6)hist[5]++;
    else if(min_d>=6 && min_d<7)hist[6]++;
    else if(min_d>=7 && min_d<8)hist[7]++;
    else if(min_d>=8 && min_d<9)hist[8]++;
    else if(min_d>=9 && min_d<10)hist[9]++;
    else;
  }
  for(int i=0;i<10;i++) printf("%4d",hist[i]);
  printf("\n");
   
  return 0;
} 

2014年10月29日星期三

批次更改檔名 in Linux

因為先前寫UVa時,檔案名稱有時會花心思改,有時就直接把題目名稱加上.cpp就貼上了
導致現在有不同的格式出現

  

現在要處理的事情很簡單

1. 去除空白
2. 將底線 ( _ ) 換成dash ( - )

經過一番查詢,終於發現最簡單的方法 - rename指令
它是基於 Perl 底下發展出來的




NAME
       rename - renames multiple files

SYNOPSIS
       rename [ -v ] [ -n ] [ -f ] perlexpr [ files ]

DESCRIPTION
       "rename" renames the filenames supplied according to the rule specified
       as the first argument.  The perlexpr argument is a Perl expression
       which is expected to modify the $_ string in Perl for at least some of
       the filenames specified.  If a given filename is not modified by the
       expression, it will not be renamed.  If no filenames are given on the
       command line, filenames will be read via standard input.

       For example, to rename all files matching "*.bak" to strip the
       extension, you might say

               rename 's/\.bak$//' *.bak

       To translate uppercase names to lower, you'd use

               rename 'y/A-Z/a-z/' *


重點來了,因為它是用 Perl expression,要稍微了解一下它的方式
不過指令本身的格式很簡單:

     rename 's/要改的部份/要變成的部份/' 目的檔案

所以操作的方式為

    rename 's/ //' *
    rename 's/_/-/' *

這樣就可以了

踏入Linux殿堂


距上次把Ubuntu裝在電腦裡頭,也有至少四五年的時間了

電腦也從原本的桌機換成現在使用的 Lenovo X201

據眾多網友所述,X系列對Ubuntu的支持性不錯

再加上想重新溫習一下過去網管的技術和經驗

所以下載了 Ubuntu 14.10,弄了一張Live SD卡

用它快速地裝了起來



令人訝異地是,現在的發行版設計的真不錯

雖然有點不習慣,但至少程式運行的效率有顯著提昇

對硬體的支援也加強了

但還是比較習慣用Terminal + vim + gcc 來編寫程式

趕緊來試寫看看UVa吧


另外還有一款可以運行在Linux的遊戲 Teeworld

技巧不是很純熟,玩起來有點癟手癟腳的

不過真的挺有趣,有興趣的可以試試看

https://www.teeworlds.com/

2014年10月28日星期二

[UVa] 10474 - Where is the Marble?


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;


int main(){

  //freopen("input.txt","r",stdin);
  int N,Q;
  int n[10000],q[10000];
  int cases=0;
  while(1){
    scanf("%d %d", &N, &Q);
    if(N==0 && Q==0)break;
    printf("CASE# %d:\n",++cases);
    memset(n,0,sizeof(n));
    memset(q,0,sizeof(q));
    for(int i=0;i<N;i++)scanf("%d",&n[i]);
    for(int i=0;i<Q;i++)scanf("%d",&q[i]);
    //for(int i=0;i<N;i++)printf("%d ",n[i]); 
    for(int i=0;i<N;i++){
      for(int j=i+1;j<N;j++){
        if(n[i]>n[j]){
          int tmp = n[i];
          n[i] = n[j];
          n[j] = tmp;
        }
      }
    }
    for(int i=0;i<Q;i++){
      for(int j=0;j<N;j++){
        if(n[j]==q[i]){
          printf("%d found at %d\n", q[i], j+1);
          break;
     }
        if(j==N-1 && n[j]!=q[i])printf("%d not found\n", q[i]);
        //break;
      }
    }
    //for(int i=0;i<N;i++)printf("%d ",n[i]); printf("\n");
    //for(int i=0;i<Q;i++)printf("%d ",q[i]); printf("\n");
   
  } 
  return 0;
}

2014年10月20日星期一

[UVa] 10420 - List of Conquests


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

int main(){
  //freopen("input.txt","r",stdin);
  char a[76]; 
  string countries[3000];  // record countries
  string buffer; //country to compare
  char tmp[100];
  int country_count[3000]; // count the girls each country
  memset(country_count,0,sizeof(country_count));
  
  int n;
  scanf("%d",&n);
  getchar();
  for(int i=0;i<n;i++){
    fgets(a,sizeof(a),stdin); //讀取一整行
    for(int j=0;j<76;j++){  
      if(a[j]!=' ')tmp[j]=a[j];  //在第一個空白出現之前,將字元存入tmp
      else break; //讀取到空白就跳出,如此僅拿取前面的國家,後面名字不理會
    }
    countries[i] = tmp; // tmp 指定給 countries[i]
  }
  sort(countries,countries+n); //按字典排序
  
  int count=0;
  for(int i=0;i<n;i++){
    if(i==0){
      buffer = countries[i];  //一開始先將第一個國家存入暫存
    }
    if(buffer == countries[i]){ //如果接下來讀取的國家和暫存器相同
      country_count[count]++;  //計數器+1
    }
    
    if(buffer != countries[i] || i == n-1){  //如果讀取的國家和暫存不同,或是讀取到最後一個項目
      cout << buffer << " " << country_count[count] << '\n'; //輸出暫存器國家,和該國家的計數
      count++; //切換到下一個國家的計數
      buffer = countries[i];  //切換到下一個國家,存入暫存
      country_count[count]++; //新國家的計數器+1
    }
  }  
  
  
  return 0;
}

[UVa] 340 - Master-Mind Hints

這和以前常玩的 _A_B 猜數字一樣
只不過可以重複猜同樣的數字
所以檢查時也要特別注意
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <cstdio>
//#include <cstring>
//#include <iostream>
using namespace std;
int main(){
  freopen("input.txt","r",stdin);
  int n;
  int game_num = 1;
  while(scanf("%d",&n)!=EOF){
    if(n==0)break;
 
    printf("Game %d:\n", game_num++); // print game number
 
    int s[n]; memset(s,0,sizeof(s)); //Secret code
    for(int i=0;i<n;i++)scanf("%d",&s[i]);  //Input secret code
 
 
 int g[n]; memset(g,0,sizeof(g)); //Guess code
 while(1){
   
   int check[n];  //檢查用的陣列,和s陣列相同
   for(int i=0;i<n;i++)check[i]=s[i]; //檢查用的陣列
 
   for(int i=0;i<n;i++)scanf("%d",&g[i]); //Input guess code
   if(g[0]==0)break; 
   
   int a=0,b=0; // hint a and b, (a,b)
   
   for(int i=0;i<n;i++) 
     if(g[i]==check[i]){
    a++;
    check[i]=0;
    g[i]=0;
     }
   for(int i=0;i<n;i++)
     for(int j=0;j<n;j++){
    if(g[i]==check[j] && g[i]!=0){
      b++;
   check[j]=0;
   g[i]=0;
    }
  }
   printf("    (%d,%d)\n",a,b);
 }
 
 //for(int i=0;i<n;i++)
    //  printf("%d ",s[i]);
 //printf("\n");
  }
  
  return 0;
}  

2014年10月6日星期一

[UVa] 10494 - If We Were a Child Again


這次直接使用大數除法來運算


1. 取得a及b的位數數目len_a、len_b
2. 將乘數b乘上10的 (len_a - len_b) 次方,也就是前移(len_a-len_b)位
3. 由i=0開始將a和b*i比較,找出滿足b*i≦A<B*(i+1)的i
4. 商的 len_a-len_b+1位 ( 即 c[len_a-len_ b ) 就是i, a = a - b*i ,b=b/10
5. 重複直到 len_a - len_b==0


//Big number : http://www.csie.ntnu.edu.tw/~u91029/BigNumber.html

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <cstring>
#include <iostream>
#define maxn 10000

using namespace std;

int len_a,len_b;  //a和b的長度

void print(int a[maxn]){
  int i=maxn-1;       // 要印的數字位置
  while(i>=0 && a[i]==0) i--; // 數字開頭的零都不印
  if(i<0)cout << '0';
  else while(i>=0) cout << a[i--]; 
}

// a > b  or  a < b
int compare(int a[maxn], int b[maxn]) 
{ 

  
  for (int i=maxn-1; i>=0; i--)    // 從高位數開始比,對應的位數相比較。
    if (a[i] != b[i] && a[i] > b[i]){       // 發現 a b 不一樣大,馬上回傳結果。
      return 1; // 1 = a>b
    }
    else if (a[i] != b[i] && a[i] < b[i]){
      return 2; // 2 = a<b
    }
    return false;       // 完全相等
}

// c = a + b;
void add(int a[maxn], int b[maxn], int c[maxn])
{
  for (int i=0; i<maxn; i++)   // 對應的位數相加
    c[i] = a[i] + b[i];
            
  for (int i=0; i<maxn-1; i++) // 一口氣進位
  {
    c[i+1] += c[i] / 10;    // 進位
    c[i] %= 10;             // 進位後餘下的數
  }
}

// c = a - b
void sub(int a[maxn], int b[maxn], int c[maxn])
{
  //code優化
  int max;
  if(len_a>=len_b)max=len_a;
  else max = len_b;
  
  for (int i=0; i<max; i++)   // 對應的位數相加
    c[i] = a[i] - b[i];
            
  for (int i=0; i<max-1; i++) // 一口氣補位
  {
    if(c[i]<0){
      c[i] += 10;
      c[i+1] --;             
    }
  }
}



// c = a * b;
void mul(int a[maxn], int b[maxn], int c[maxn])
{
  //code優化
  int max;
  if(len_a>=len_b)max=len_a;
  else max = len_b;
  
  for (int i=0; i<max; i++)
    c[i] = 0;
     
    for (int i=0; i<max; i++)
      for (int j=0; j<max; j++)
        if (i+j < max)
          c[i+j] += a[i] * b[j];
                    
    for (int i=0; i<max-1; i++) // 一口氣進位
    {
      c[i+1] += c[i] / 10;
      c[i] %= 10;
    }
}

// c = a / b
void div(int a[maxn], int b[maxn], int c[maxn])
{
    //code 優化
    int max=0;
    if(len_a>=len_b)max=len_a+1;
    else max = len_b+1;
    
    int  t[maxn]={0};
    int  t2[maxn]={0};
    int  b2[maxn]={0};
    int  b3[maxn]={0};
    
    int len_diff = len_a-len_b; //兩數字位數差 difference of length
    memset(t,0,sizeof(t));
    t[len_diff]=1; //t陣列的用意是,創造一個"...001000..."的陣列,好讓除數可以乘上
    
    while(len_diff >= 0){
        memset(b2,0,sizeof(b2));        
        mul(b,t,b2); //b2 = b * t
        
        for(int i=9;i>0;i--){  //商數由9→1
          memset(b3,0,sizeof(b3));
          for(int j=max-1;j>=0;j--){
            b3[j] = b2[j] * i; // b3 = b2 * i ,測試商數 
          } 
          for(int j=0;j<max;j++){
            while(b3[j]>=10){  //所有位數進位
              b3[j]-=10;
              b3[j+1]+=1;
            }
          }
          if(compare(a,b3)==1 || compare(a,b3)==0){ //若a>=b3
            c[len_diff]+=i; // 於len_diff的商數+1
            sub(a,b3,t2);   // t2 = a - b3 
            for(int j=0;j<max;j++)a[j]=t2[j];  //a = t2
            memset(t2,0,sizeof(t2));
          }

        }

        memset(t,0,sizeof(t));
        len_diff--; //位數往前一位
        if(len_diff>=0)t[len_diff]=1;
    }
    
}

void mod(int a[maxn], int b[maxn], int c[maxn])
{

    //code 優化
    int max=0;
    if(len_a>=len_b)max=len_a;
    else max = len_b;
    
    int  t[maxn]={0};
    int  t2[maxn]={0};
    int  b2[maxn]={0};
    int  b3[maxn]={0};

    int len_diff = len_a-len_b; //兩數字位數差
    t[len_diff]=1;

    while(len_diff>=0){
        memset(b2,0,sizeof(b2));        
        mul(b,t,b2);    
        for(int i=9;i>0;i--){
          memset(b3,0,sizeof(b3));
          for(int j=max-1;j>=0;j--){
            b3[j] = b2[j] * i;
            while(b3[j]>=10){
              b3[j]-=10;
              b3[j+1]+=1;
            }
          }
          
          if(compare(a,b3)==1 || compare(a,b3)==0){
            sub(a,b3,t2);
            for(int j=0;j<max;j++)a[j]=t2[j]; // a = t2
            for(int j=0;j<max;j++)c[j]=t2[j]; // c = t2
            memset(t2,0,sizeof(t2)); 
          }


        }
        memset(t,0,sizeof(t));
        len_diff--;
        if(len_diff>=0)t[len_diff]=1;
    }
}


char input_a[maxn]={'\0'};
char op,op1,op2,op3;
char input_b[maxn]={'\0'};
int a[maxn],b[maxn],result[maxn];

int main(){
  freopen("input.txt","r",stdin);
  while(scanf("%s%s%s",&input_a,&op2,&input_b)!=EOF){
    memset(a,'\0',sizeof(a));
    memset(b,'\0',sizeof(b));
      memset(result,'\0',sizeof(result));
    
    //printf("%s %c %s\n",input_a,op2,input_b);
    
    //轉換為倒轉數字陣列
    len_a = strlen(input_a);
    for(int i=0;i<len_a;i++){
      a[i]=input_a[len_a-i-1]-48;
    }
    len_b = strlen(input_b);
    for(int i=0;i<len_b;i++){
      b[i]=input_b[len_b-i-1]-48;
    }
      
      if(op2=='/'){
        if(compare(a,b)==2)printf("0"); //若b>a,則為0
        else if(len_b==1 && b[0]==0)break;
        else {
          div(a,b,result);
          print(result);
        }
      }
      if(op2=='%'){
        if(compare(a,b)==2)print(a); //若b>a,餘數則為a
        else {
          mod(a,b,result);
          print(result);
        }
      }
      printf("\n");

  }
  
  return 0;  
} 







2014年10月2日星期四

[UVa] 748 - Exponentiation

比較難處理的一題
這邊要將前面和後面的0通通去掉
在 print 函數裡下了不少工夫
大數運算參考 演算法筆記  - Big Number
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <cstring>
#include <iostream>
#define maxn 1000
using namespace std;
// print

int dot;
void print(int a[maxn]){
  int i=maxn-1;       // 要印的數字位置
  int stop=0; 
  int dot_appear=0;
  while(i>=0 && a[i]=='\0' && i+1>dot) i--; // 數字開頭的零都不印
  if(i<0)cout << '0';
  else while(i>=0 && stop!=1) { //stop不等於1時,持續輸出數字
 if(i+1==dot){
   cout << '.';
   dot_appear=1;
 }
 if(dot_appear==1){ //從輸出小數點後,針對後面的數字做檢查
   stop=1; //若後面皆為0,則stop=1
   for(int j=i;j>=0;j--){
     if(a[j]!=0){ //若後面有非0者,stop=0
       stop=0; break;
     }
   }
 }
 if(stop!=1)cout << a[i]; 
 i--;
  }
}
 // c = a * b;
void mul(int a[maxn], int b[maxn], int c[maxn]){
  for (int i=0; i<maxn; i++)
    c[i] = 0;
     
    for (int i=0; i<maxn; i++)
      for (int j=0; j<maxn; j++)
        if (i+j < maxn)
          c[i+j] += a[i] * b[j];
                    
    for (int i=0; i<maxn-1; i++) // 一口氣進位
    {
      c[i+1] += c[i] / 10;
      c[i] %= 10;
    }
}

char input[maxn]; 
int a[maxn],b[maxn],result[maxn];

int main(){
  freopen("input.txt","r",stdin);
  for(int i=0;i<maxn;i++)a[i]='\0';
  for(int i=0;i<maxn;i++)b[i]='\0';
  for(int i=0;i<maxn;i++)result[i]='\0';
  
  while(scanf("%s",&input)!=EOF){
    
 //紀錄小數點後有幾位
 dot=0;
 int len = strlen(input);
 for(int i=len-1;i>0;i--){
   if(input[i]=='.')break;
   dot++;
 }
 
 //change input into integer array
    for(int i=0;i<len;i++){
   a[i]=input[len-i-1]-48;
 }
 
 //將小數點去掉
 for(int i=dot;i<len;i++){
   a[i]=a[i+1];
   a[i+1]=0;
 }
 
 
 for(int i=0;i<maxn;i++)b[i]=a[i]; //將a複製給b
 
 int n;
 scanf("%d",&n);
 dot *= n; //乘幾次,小數點後位數就加倍幾次
 n--;
 while(n--){
   mul(a,b,result); //每次的b乘給a
   for(int i=0;i<maxn;i++)b[i]=result[i]; //將result複製給b
 }
 
 /*
 for(int i=0;i<maxn;i++){
   if(result[i]==0)printf("%d",result[i]);
   else if(result[i]=='\0'); 
   else printf("%d",result[i]);
 }
 */
 //printf("\n");
    print(result);
    printf("\n");
 
  }
  
  return 0;  
} 

2014年10月1日星期三

[UVa] 465 - Overflow

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <cstring>
#include <iostream>

#define maxn 1000 
// E.X. max of int is 2147483647


using namespace std;

// print
void print(int a[maxn]){
  int i=maxn-1;       // 要印的數字位置
  while(i>=0 && a[i]==0) i--; // 數字開頭的零都不印
  if(i<0)cout << '0';
  else while(i>=0) cout << a[i--]; 
}

// a > b  or  a < b
int compare(int a[maxn], int b[maxn]) 
{
  for (int i=maxn-1; i>=0; i--)    // 從高位數開始比,對應的位數相比較。
    if (a[i] != b[i] && a[i] > b[i]){       // 發現 a b 不一樣大,馬上回傳結果。
   return 1; // 1 = a>b
 }
 else if (a[i] != b[i] && a[i] < b[i]){
   return 2; // 2 = a<b
 }
    return false;       // 完全相等
}

// c = a + b;
void add(int a[maxn], int b[maxn], int c[maxn])
{
  for (int i=0; i<maxn; i++)   // 對應的位數相加
    c[i] = a[i] + b[i];
            
  for (int i=0; i<maxn-1; i++) // 一口氣進位
  {
    c[i+1] += c[i] / 10;    // 進位
    c[i] %= 10;             // 進位後餘下的數
  }
}

// c = a * b;
void mul(int a[maxn], int b[maxn], int c[maxn])
{
  for (int i=0; i<maxn; i++)
    c[i] = 0;
     
    for (int i=0; i<maxn; i++)
      for (int j=0; j<maxn; j++)
        if (i+j < maxn)
          c[i+j] += a[i] * b[j];
                    
    for (int i=0; i<maxn-1; i++) // 一口氣進位
    {
      c[i+1] += c[i] / 10;
      c[i] %= 10;
    }
}


char max_int[maxn] = "2147483647";
char input_a[maxn]={'\0'};
char op1,op2,op3;
char input_b[maxn]={'\0'};
int a[maxn],b[maxn],intmax[maxn],result[maxn];

int main(){
  for(int i=0;i<maxn;i++)a[i]=0;
  for(int i=0;i<maxn;i++)b[i]=0;

  while(scanf("%s",&input_a)!=EOF){
      scanf("%c%c%c",&op1,&op2,&op3);
   scanf("%s",&input_b);
   printf("%s %c %s\n",input_a,op2,input_b);
   
   
   //change input into integer array
   int len = strlen(input_a);
      for(int i=0;i<len;i++){
     a[i]=input_a[len-i-1]-48;
   }
   
   len = strlen(input_b);
   for(int i=0;i<len;i++){
     b[i]=input_b[len-i-1]-48; 
   }
   
   len = strlen(max_int);
      for(int i=0;i<len;i++){
     intmax[i]=max_int[len-i-1]-48; 
   }

   
   
   int cmp_a = compare(a,intmax);
   if(cmp_a==1)printf("first number too big\n");
 
   int cmp_b = compare(b,intmax);
   if(cmp_b==1)printf("second number too big\n");

   if(op2=='+')add(a,b,result);
   if(op2=='*')mul(a,b,result);   
   
   int cmp_result = compare(result,intmax);
   if(cmp_result==1)printf("result too big\n");
   
   memset(a,0,sizeof(a));
   memset(b,0,sizeof(b));
   memset(result,0,sizeof(result));
  }

  return 0;  
} 

2014年9月27日星期六

[UVa] 10106 - Product

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <cstring>
#include <iostream>

#define maxn 1000
using namespace std;

void print(int a[maxn]){
  int i=maxn-1;       // 要印的數字位置
  while(i>=0 && a[i]==0) i--; // 數字開頭的零都不印
  if(i<0)cout << '0';
  else while(i>=0) cout << a[i--]; 
}

// c = a + b;
void add(int a[maxn], int b[maxn], int c[maxn])
{
  for (int i=0; i<maxn; i++)   // 對應的位數相加
    c[i] = a[i] + b[i];
            
  for (int i=0; i<maxn-1; i++) // 一口氣進位
  {
    c[i+1] += c[i] / 10;    // 進位
    c[i] %= 10;             // 進位後餘下的數
  }
}

// c = a * b;
void mul(int a[maxn], int b[maxn], int c[maxn])
{
  for (int i=0; i<maxn; i++)
    c[i] = 0;
     
    for (int i=0; i<maxn; i++)
      for (int j=0; j<maxn; j++)
        if (i+j < maxn)
          c[i+j] += a[i] * b[j];
                    
    for (int i=0; i<maxn-1; i++) // 一口氣進位
    {
      c[i+1] += c[i] / 10;
      c[i] %= 10;
    }
}

char input[maxn]={'\0'};
int a[maxn],b[maxn],c[maxn];

int main(){
  freopen("input.txt","r",stdin);
  while(scanf("%s",input)!=EOF){
 int len = strlen(input);
    for(int i=0;i<len;i++)
   a[i]=input[len-i-1]-48;

 for(int i=0;i<maxn;i++)input[i]='\0';
 
 scanf("%s",input);
 len = strlen(input);
 for(int i=0;i<len;i++)
   b[i]=input[len-i-1]-48;
 
 mul(a,b,c);
 print(c);
    printf("\n"); 
 
 for(int i=0;i<maxn;i++)a[i]=0;
 for(int i=0;i<maxn;i++)b[i]=0;
  }
  return 0;
} 

2014年9月26日星期五

[UVa] 424 - Integer Inquiry

本題參考了演算法筆記的大數運算

簡單解決
 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
void print(int a[200]){
  int i=200-1;       // 要印的數字位置
  while(i>=0 && a[i]==0) i--; // 數字開頭的零都不印
  if(i<0)cout << '0';
  else while(i>=0) cout << a[i--]; 
}
// c = a + b;
void add(int a[200], int b[200], int c[200])
{
  for (int i=0; i<200; i++)   // 對應的位數相加
    c[i] = a[i] + b[i];
            
  for (int i=0; i<200-1; i++) // 一口氣進位
  {
    c[i+1] += c[i] / 10;    // 進位
    c[i] %= 10;             // 進位後餘下的數
  }
}
char input[200]={'\0'};
int a[200],c[200];

int main(){
  
  while(1){
    gets(input);
 if(input[0]=='0'){
   print(c);
   printf("\n"); //本題需要留一個換行
   break;
 }
 int len = strlen(input);
    for(int i=0;i<len;i++){
   a[i]=input[len-i-1]-48;
 }
 add(a,c,c);
 for(int i=0;i<200;i++)a[i]=0;
  }
  return 0;
}
 

2014年9月21日星期日

[UVa] 10115 - Automatic Editing

 

http://www.cplusplus.com/reference/cstring/strstr/?kw=strstr



有兩個關於字串操作的函數相當有用,一個是strstr,比較str2是否在str1中,有的話傳回在str1的指標位址,如下: 



strstr

const char * strstr ( const char * str1, const char * str2 );
      char * strstr (       char * str1, const char * str2 );
Locate substring
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.

The matching process does not include the terminating null-characters, but it stops there.

/* strstr example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="This is a simple string";
  char * pch;
  pch = strstr (str,"simple");
  strncpy (pch,"sample",6);
  puts (str);
  return 0;
}


This example searches for the "simple" substring in str and replaces that word for "sample".

Output:

This is a sample string



另外就是常用的strcpy,若source指定的位置在字串中間時,會從指定的位置開始拷貝到字串的結尾(\0)處。

strcpy

char * strcpy ( char * destination, const char * source );
Copy string
Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).

To avoid overflows, the size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character), and should not overlap in memory with source.




#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h> 
char str[300]={'\0'};
char find[10][100]={'\0'};
char replace[10][100]={'\0'};
char str1[300]={'\0'};


char str2[300]={'\0'};
char str3[300]={'\0'};

int main(){
  freopen("input.txt", "r", stdin);

  int n;
  while(1){
    scanf("%d",&n);
 getchar();
 //printf("n=%d\n",n);
    if(n==0)break;
 
 int tmp=n;
    while(n--){ //輸入所有find和replace-by
   //printf("%d",n);
   gets(find[tmp-n-1]);
   gets(replace[tmp-n-1]);
 }
 /*
 for(int i=0;i<tmp;i++){
   puts(find[i]);
   puts(replace[i]);
 }
 */
 gets(str); //輸入要檢驗的字串
 //puts(str);
 //getchar();
 //printf("test");
 for(int i=0;i<tmp;i++){
   if(strstr(str,find[i])!=NULL){
     char *pch = strstr(str,find[i]);
  int len = strlen(find[i]);
  strcpy(str1,pch+len);
  *pch = '\0';
  strcat(str,replace[i]);
  strcat(str,str1);
  i--;
  //puts(str);
   }
 
 }
 puts(str);
 
  }

  return 0;
}

2014年9月19日星期五

[Uva] 644 - Immediate Decodability


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h> 
char codes[12][12]={'\0'};
int main(){
  
  freopen("input.txt", "r", stdin);


  int a=0;
  int set=1;
  int decodable[12]={0}; //儲存每一record和前面所有record比較,找不到字首相同,則為可編碼
  while(scanf("%s",codes[a])!=EOF){
    
 decodable[0]=1; //第一個record因為只能和自己比,故先設為1
 if(codes[a][0]!='9'){
  for(int i=0;i<a;i++){ 
    if(a==0){  //若為第一個狀況,則先跳出
     break;
    }
    int flag=0;
    while(1){
     //printf("%c %c\n",codes[i][flag],codes[a][flag]);
     if(codes[a][flag]==codes[i][flag]){  //若檢查為相同的字
    flag++; //旗標往下一位元跳
    decodable[a]=0; //暫定此record的可編碼為0 
     }
     //若其中一項record的下一字元為'\0'且可編碼依然為0,則跳出
     if((codes[a][flag]=='\0'||codes[i][flag]=='\0') && decodable[a]==0)
    break;
     //若在兩項record都還沒到'\0',且發現兩位元不同,則為可編碼
     if(codes[a][flag]!=codes[i][flag]&&codes[i][flag]!='\0'&&codes[a][flag]!='\0'){
    decodable[a]=1;
    break;
     }
    }
    if(decodable[a]==0)break;
  }
 }
 
 
 
 if(codes[a][0]=='9'){
   for(int i=0;i<a;i++){
     if(decodable[i]==0){ //若發現其中一項為0,則為不可編碼
    printf("Set %d is not immediately decodable\n",set);
    a=-1;
    break;
  }
  if(i==(a-1) && decodable[i]==1){ //若i已經到了第a-1項且依然為1
    a=-1;
    printf("Set %d is immediately decodable\n",set);
  }
   }
   set++;
   memset(decodable,0,sizeof(int)); //初始化
    }
 a++;
  }   

  
  return 0;
} 

2014年9月16日星期二

[UVa] 10815 - Andy's First Dictionary

這題我採用 Trienode的資料結構,直接做字典順序輸出
詳細請參閱 http://en.wikipedia.org/wiki/Trie 
 http://openhome.cc/Gossip/CGossip/
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h> 

char input[300]={'\0'};
char words[6000][300]={'\0'};

//建構Tire字典樹
struct TrieNode{
  TrieNode* l[128]; //128種字元,皆為Trienode型別,以l陣列儲存
  int n; //計算字串出現次數,0則代表沒有這個字
  TrieNode() //Trienode函數
  {
    memset(l, 0, sizeof(TrieNode*) *128); //把l陣列裡的指標都設為0
    n = 0;
  }
}*root = new TrieNode(); //root為第一個TrieNode

//插入字串
void add(char* s)
{
 TrieNode* p = root; //p為指向root節點的指標,
 for (; *s; ++s) // *s= s指向的變數,若尚有字元,則++s
 {   //若l陣列中第s欄位的指標不存在,則新增一節點
  if ( !(p->l[*s]) ) p->l[*s] = new TrieNode();
  p = p->l[*s];
 }
 //p->n++;
 p->n=1; //1代表有此單次,因只要輸出一次,所以p->n設為1即可
}

char w[300+1];   // 300個字的字串
void traversal(TrieNode* p, char* s) //s指標指向w
{
 *s = '\0';  
 for (int i=0; i<(p->n); ++i)
  printf("%s\n",w);

 for (int i=0; i<128; ++i)
  if (p->l[i]) //若l[i]存在有指標
  {
   *s = i; //s指向的變數設為i
   traversal(p->l[i], s+1); //往下一個Trienode節點探詢,s指標往w的下一位前進
  }
}

//釋放記憶體空間
void release(TrieNode* p = root)
{
 for (int i=0; i<26; ++i)
  if (p->l[i])
   release(p->l[i]);
 delete p;
}



int main(){
  freopen("input.txt", "r", stdin);
  //printf("%d\n", sizeof(TrieNode*));
  while(fgets(input, sizeof(input), stdin) ){  /*讀到EOF會自動跳出*/
    //gets(input);
 
 int len=strlen(input); // len = input長度
 for(int i=0;i<len;i++){
   if(!isalpha(input[i])){
     input[i]=' ';   //去除非字母字元
      }
      //大寫換小寫
   if(input[i]>='A'&&input[i]<='Z')input[i]+=32;
    }
 
 char word[300]={'\0'};
 int start_read=0, flag=0;
 for(int i=0;i<len;i++){
   ////該字元為字母且前一個不是字元,或該字元為列首時,start_read=1
   if(isalpha(input[i]) && (!isalpha(input[i-1]) ||i==0) ){ 
     start_read=1;
  flag=0;
   }
   if(start_read==1){ //start_read維持在1時,字元存入word陣列
     word[flag]=input[i];
  flag++;
   }
   if(isalpha(input[i])&&!isalpha(input[i+1])){
     start_read=0;
  flag=0;
  //puts(word);
  add(word); //插入到Trie
  
  //清空陣列
  memset(word,'\0',sizeof(word));
  //for(int j=0;j<300;j++)word[j]='\0';
   }
   
 }
 //puts(input);
 //system("PAUSE");
  }
  
  traversal(root,w);
  
  release(root);
  return 0;
} 

2014年9月13日星期六

[UVa] 10878 - Decode the tape


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h> 
int code[11]={64,32,16,8,4,2,1};
char input[20]={'\0'};
int main(){
  freopen("input.txt", "r", stdin);
  int end_count=0;
  while(1){
    int output=0;
    gets(input);
 //puts(input);
 if(input[0]=='_')end_count++;
 if(end_count==2)break;
    
 if(input[0]!='_'){
   if(input[2]=='o')output+=64;
   if(input[3]=='o')output+=32;
   if(input[4]=='o')output+=16;
   if(input[5]=='o')output+= 8;
   if(input[7]=='o')output+= 4;
   if(input[8]=='o')output+= 2;
   if(input[9]=='o')output+= 1;
   
   printf("%c",output);
 }
 
 
 //system("PAUSE");
  }
  return 0;

}

[UVa] 409 - Excuses, Excuses!


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h> //isalpha
char keywords[30][100]={'\0'};
char line[30][100]={'\0'};
char new_line[30][100]={'\0'};
int count[30]={0};
int main(){
  freopen("input.txt", "r", stdin);

  int K,E;
  int max=0;
  int excuse=1;
  while(scanf("%d %d",&K,&E)!=EOF){
    
 getchar();
 
 //輸入關鍵字詞
    for(int i=0;i<K;i++){
   gets(keywords[i]);
 }
 //getchar();
 
 //輸入辯詞
 for(int i=0;i<E;i++){
   gets(line[i]);
   
   int len=strlen(line[i]); //獲得line長度
   for(int j=0;j<len;j++)
     new_line[i][j]=line[i][j]; //Copy一份至new_line
   for(int j=0;j<len;j++){ //消除new_line裡所有非字母符號
     if(!isalpha(new_line[i][j])){
     new_line[i][j]=' ';  
  }
  if(new_line[i][j]>='A'&&new_line[i][j]<='Z')new_line[i][j]+=32; //所有大寫換小寫
   }
   //puts(line[i]);
   //puts(new_line[i]);
 }
 
 for(int w=0;w<K;w++) //每個keyword都跑一次
  for(int i=0;i<E;i++){  //每個excuse都跑一次
   int match=0, start=0, flag=0,flag2=0;
   while(new_line[i][flag]!='\0'){
       //如果在excuse中檢查到和單字字首相同,且前一個字元不為字母時,start=1
       if(new_line[i][flag]==keywords[w][0]&&!isalpha(new_line[i][flag-1]))start=1;
    if(new_line[i][flag]==keywords[w][flag2]&&start==1){ //之後的檢查,在start=1的前提下進行
      match=1;  //依然和單字相同時,match維持為1
      flag++;
      flag2++;
    }else{
      start=0;  //一檢查到不是,則start=0、match=0,flag2回到單字起點
      match=0;
      flag++;
      flag2=0;
    }
    //如果檢查到單字字尾,且excuse中後一個字元不為字母,且match=1時,該excuse的單字計數+1
    if( (keywords[w][flag2]=='\0') && (!isalpha(new_line[i][flag])) && (match==1) ){
      count[i]++;
    }
   }
   
 }
 
 printf("Excuse Set #%d\n", excuse);
 excuse++;
 for(int i=0;i<E;i++){
   if(count[i]>=max)max=count[i];
 }
 for(int i=0;i<E;i++){
   if(count[i]==max)puts(line[i]);
 }
 
 //for(int i=0;i<E;i++)printf("%d ",count[i]);
 
 printf("\n");
 
 for(int i=0;i<30;i++)count[i]=0;
 max=0;
  }
  return 0;
}

2014年9月6日星期六

[UVa] 537 - Artificial Intelligence?


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char line[10000]={'\0'};

int main(){
  //freopen("input.txt", "r", stdin);

  int n;
  scanf("%d",&n);
  getchar();
  int cases=n;
  while(n--){
    printf("Problem #%d\n",cases-n); //輸出problem數
    gets(line);
 double P=0,U=0,I=0;
 int enableP=0, enableU=0, enableI=0; //宣告是否出現變數的檢查變數
    for(int i=0; i<strlen(line); i++){ 
   char buffer[1000];
   int j=0,flag;
   
   
   //搜尋到"P=___mW"
   for(int p=0;p<1000;p++)buffer[p]='\0';
   flag=0;
   if(line[i]=='P' && line[i+1]=='='){ 
     enableP=1;
     for(j=i+2; (line[j]<='9'&&line[j]>='0')||line[j]=='.' ; j++){
    buffer[flag]=line[j];
    flag++;
  }
  double tmp = atof(buffer); 
  if(line[j]=='m')tmp/=1000;
  if(line[j]=='k')tmp*=1000;
  if(line[j]=='M')tmp*=1000000;
  P = tmp;
   }
   
   //搜尋到"U=___kV"
   for(int p=0;p<1000;p++)buffer[p]='\0';
   flag=0;
   if(line[i]=='U' && line[i+1]=='='){ 
     enableU=1;
     for(j=i+2; (line[j]<='9'&&line[j]>='0')||line[j]=='.' ; j++){
    buffer[flag]=line[j];
    flag++;
  }
  double tmp = atof(buffer); 
  if(line[j]=='m')tmp/=1000;
  if(line[j]=='k')tmp*=1000;
  if(line[j]=='M')tmp*=1000000;
  U = tmp;
   }
   
   //搜尋到"I=___MA"
   for(int p=0;p<1000;p++)buffer[p]='\0';
   flag=0;
   if(line[i]=='I' && line[i+1]=='='){ 
     enableI=1;
     for(j=i+2; (line[j]<='9'&&line[j]>='0')||line[j]=='.' ; j++){
    buffer[flag]=line[j];
    flag++;
  }
  double tmp = atof(buffer);
  if(line[j]=='m')tmp/=1000;
  if(line[j]=='k')tmp*=1000;
  if(line[j]=='M')tmp*=1000000;
  I = tmp;
   }
   
 }
 //printf("P=%.2f  U=%.2f  I=%.2f \n", P, U, I);
 
 if(enableP==0)printf("P=%.2fW\n", U*I);
 if(enableU==0)printf("U=%.2fV\n", P/I);
 if(enableI==0)printf("I=%.2fA\n", P/U);
 //for(int i=0;line[i];i++)printf("%c",line[i]);
 
 printf("\n");
  
  }
  return 0;
} 

C++ 字串整數轉換

資料來源: Edison.X. Blog

需要先引入標頭檔
#include <stdlib.h>  or  #include <cstdlib>

1. atof:將字串轉為倍精度浮點數
double atof ( const char * str );
ex:
 char buffer[] = "2.675";
 double f = atof(buffer);

2. atoi:將字串轉為整數
 int atoi ( const char * str );
ex:
 char buffer[] = "23";
 int i = atoi(buffer);

3. atol:將字串轉為長整數
long int atol ( const char * str );
ex:
 char buffer[] = "23";
 long int i = atol(buffer);

4. strtod: 將字串轉為倍精度浮點數
double strtod ( const char * str, char ** endptr );
ex:
 char buffer[] = "1011.113";
 double a = strtod(buffer, NULL);

5. strtol:將字串視為任意進制,轉為長整數
long int strtol ( const char * str, char ** endptr, int base );
ex:
 char buffer[] = "1011";
 long a = strtol(buffer, NULL,2);
// 將 "1011" 視為2進制,轉完之後 a 即為 11

6. strtoul:將字串視為任意進制,轉為無號長整數
unsigned long int strtoul ( const char * str, char ** endptr, int base );
ex:
 char *buffer = "1011";
 unsigned long a = strtoul(buffer, NULL,2);
// 將 "1011" 視為2進制,轉完之後 a 即為 11

 7. itoa: 整數轉為任意進制字串 (非標準函式)
char* itoa(int value, char* string, int radix);
ex:
char buffer[200];
int value = 234;
itoa(value, buffer, 2); // 將 234 轉為存成2進制之字串

8. ltoa:長整數轉為任意進制字串 (非標準函式)
char* ltoa(long int value, char* string, int radix);
ex:
char buffer[200];
lnt value = 234;
ltoa(value, buffer, 2); // 將 234 轉為存成2進制之字串

9. strtod, strtol, strtoul 使用技巧
若有一字串裡面有二個浮點數,以空白為分隔符號
則可以下列方式取出
char buffer[] = "1.1   2.2";
char *pEnd ;
double d1, d2;
d1 = strtod(buffer, &pEnd);
d2 = strtod(pEnd, NULL);
若有若干浮點數,這些浮點數以空白為分隔符號
則可使用下列技巧依序取出浮點數
char buffer[] = "1.12 2.2 3.3 4.455 5.5123";
char *pStart = buffer;
char *pEnd = NULL;
double d;

while(1){
      d = strtod(pStart, &pEnd);
      if(pStart==pEnd) break;
      else pStart = pEnd;
      printf("%lf\n", d);
}
同理, strtol, strtoul 也是相同技巧。

10. 擅用 sprintf 與 sscanf
(10.1) sscanf - 字串轉整數、無號數、浮點數..
ex1 :
 char buffer[] = "-5, 10, 2.3, string";
 int i;
 unsigned u;
 double d;
 char buf2[200];
 sscanf(buffer, "%d, %u, %lf, %s", &i, &u, &d, &buf2);
 printf("%d, %u, %lf, %s\n", i, u, d, buf2);
ex2:  char demo[] = "1,2,3,4,5";
 char *ptr = demo;
 int a[5];
 int i=0, INT=0;
 while(sscanf(ptr, "%d,%s", &INT, ptr)==2) a[i++] = INT;
 a[i] = INT;
 for(i=0; i<5; i++) printf("%d ", a[i]);
(10.2) sprintf - 浮點數、整數、字串... 轉字串
ex: int a=0;
float b = 1.2;
char demo[] = "Test";
char dest[200];
sprintf(dest, "%d %f %s", a, b, demo);

2014年9月5日星期五

[UVa] 10361 - Automatic Poetry


久違的AC,注意換行符號不要存入s2~s5
輸出line2後再換行即可


#include <stdio.h>
#include <string.h>
char line1[10000]={'\0'};
char line2[10000]={'\0'};

int main(){
  //freopen("input.txt", "r", stdin);
  //freopen("output.txt", "w", stdout);
  int n;
  scanf("%d",&n);
  getchar();
  while(n--){

    gets(line1);
    gets(line2);
    
    for(int i=0;i<strlen(line1);i++){
      if(line1[i]=='<' || line1[i]=='>'){}else printf("%c",line1[i]);
    }
    printf("\n");
    
    
    char s2[1000]={'\0'};
    char s3[1000]={'\0'};
    char s4[1000]={'\0'};
    char s5[1000]={'\0'};
    int flag=0,start_read=0,r=0,count=0;
    for(flag=0;flag<strlen(line1);flag++){
      if(start_read==1 && line1[flag]!='<' && line1[flag]!='>' && line1[flag]!='\n'){
        if(count==1)s2[r]=line1[flag];
        if(count==2)s3[r]=line1[flag];
        if(count==3)s4[r]=line1[flag];
        if(count==4)s5[r]=line1[flag];
        r++;
      }
      if(line1[flag]=='<'||line1[flag]=='>'){
        start_read=1;
        r=0;
        count++;
      }
    }
    
    int len2 = strlen(line2);
    for(flag=0;flag<len2;flag++){
      if(line2[flag]!='.')
        printf("%c", line2[flag]);
      else if(line2[flag]=='.'){
        for(int i=0;i<strlen(s4);i++)
          printf("%c",s4[i]);
        for(int i=0;i<strlen(s3);i++)
          printf("%c",s3[i]);
        for(int i=0;i<strlen(s2);i++)
          printf("%c",s2[i]);
        for(int i=0;i<strlen(s5);i++)
          printf("%c",s5[i]);
        break;
      }
      else ;
    }
    
    
    printf("\n");
    for(int i=0;i<1000;i++)line1[i]='\0';
    for(int i=0;i<1000;i++)line2[i]='\0';
    for(int i=0;i<1000;i++)s2[i]='\0';
    for(int i=0;i<1000;i++)s3[i]='\0';
    for(int i=0;i<1000;i++)s4[i]='\0';
    for(int i=0;i<1000;i++)s5[i]='\0';
  }
  return 0;
} 

2014年9月3日星期三

[UVa] 401 - Palindromes


#include <stdio.h>
#include <string.h>
char c[100]={'\0'};
char mirror[]="AAE3HHIIJLLJMMOOS2TTUUVVWWXXYYZ500112S3E5Z88"; //建立鏡像對照表
int is_mirror(char a, char b){
  for(int i=0;i<strlen(mirror);i++){
    if(a==mirror[i] && b==mirror[i+1]){  //如果此字元和下一字元比較相同,傳回1
   return 1;
 }
  }
  //沒回傳則傳回0
  return 0;
}
int main(){
   //freopen("input.txt", "r", stdin);
   //freopen("output.txt", "w", stdout);

  while(scanf("%s",c)!=EOF){
    for(int i=0;i<100;i++)if(c[i]==' ')c[i]='\0'; //把字串之後的空白也初始化為\0
    int ispalin=1 , ismirror=1;
 //printf("%d\n", strlen(c));

 for(int i=0;i<strlen(c)/2;i++){//比較回文
   if(c[i]!=c[strlen(c)-i-1]){
     ispalin=0;
   }
 }
 for(int i=0;i<strlen(c);i++){//比較字串
   if(!is_mirror(c[i], c[strlen(c)-i-1])){
     ismirror=0;
   }
 }
 
    if(ispalin && !ismirror)printf("%s -- is a regular palindrome.\n\n",c);
 if(!ispalin && ismirror)printf("%s -- is a mirrored string.\n\n",c);
 if(ispalin && ismirror)printf("%s -- is a mirrored palindrome.\n\n",c);
 if(!ispalin && !ismirror)printf("%s -- is not a palindrome.\n\n",c);
 for(int i=0;i<25;i++)c[i]='\0';
  }
  return 0;
} 

2014年9月1日星期一

[UVa] 457 - Linear Cellular Automata


#include <stdio.h>
#include <string.h>
int DNA[10],dish[40]={0},dish_next[40]={0},cases;
int main(){
   //freopen("input.txt", "r", stdin);
   //freopen("output.txt", "w", stdout);
   
   
   scanf("%d",&cases);
   while(cases--){
     //getchar();
     for(int i=0;i<10;i++)scanf("%d",&DNA[i]);
     //for(int i=0;i<10;i++)printf("%d ",DNA[i]);
     dish[19]=1;
     for(int i=0;i<40;i++){
       if(dish[i]==1)printf(".");
         else if(dish[i]==2)printf("x");
         else if(dish[i]==3)printf("W");
         else printf(" ");
     }
     printf("\n");
     for(int i=0;i<49;i++){
       for(int k=0;k<40;k++){
         if(k==0)dish_next[k] = DNA[ dish[k]+dish[k+1] ];
         else if(k==39)dish_next[k] = DNA[ dish[k]+dish[k-1] ];
         else dish_next[k] = DNA[ dish[k-1]+dish[k]+dish[k+1] ];
       }
       for(int i=0;i<40;i++){
         if(dish_next[i]==1)printf(".");
         else if(dish_next[i]==2)printf("x");
         else if(dish_next[i]==3)printf("W");
         else printf(" ");
         dish[i] = dish_next[i];
       }
       printf("\n");
     }
     for(int i=0;i<40;i++){
       dish[i]=0;
       dish_next[i]=0;
     }
     if(cases)printf("\n"); //重要!檢查是否已經到最後了,最後不能輸出兩空行
   }
   return 0;
} 

2014年8月31日星期日

[UVa] 694 - The Collatz Sequence


#include <stdio.h>
long long A,L; //避免乘法溢出
int cases=0;
int main(){
  while(scanf("%lld %lld",&A,&L)!=EOF&&A>0&&L>0){ //在UVa中,要用lld才行
    cases++;
    printf("Case %d: A = %lld, limit = %lld, ",cases,A,L);
    int count=0;
    while(1){
   if(A>L){
     break;
   }
   if(A==1){
     count++;
     break;
   }
   else if(A%2==0){
     A=A/2;
  count++;
   }else{
     A=A*3+1;
  count++;
   }
 }
 printf("number of terms = %d\n",count);
 
  }
  return 0;
} 

2014年8月30日星期六

[UVa] 489 - Hangman Judge

#include <stdio.h>
#include <string.h>
char c[101]={'\0'},s[101]={'\0'};
int round,fail=0,lose=0;
int main(){
  while(scanf("%d",&round)!=-1){
    if(round==-1)break;
    printf("Round %d\n",round);
 scanf("%s",&s); //solution
 scanf("%s",&c); //string to guess
 
 lose=0;
    for(int i=0;i<100;i++){
   fail=1; //set fail = 1
   for(int j=0;j<100;j++){
     if(c[i]==s[j]){
    fail=0; //有檢查到相同的字元,則本次猜測成功,fail設為0
    s[j]='\0'; //將被猜到的相同字元都換成'\0'
  }
   }
   if(fail==1)lose++; //沒檢查到相同字元,本次猜測失敗,lose++
   
   char check = c[i]; //將原字串內本次猜測的字都換為'\0',避免重複猜測
   for(int j=0;j<100;j++)
     if(c[j]==check)c[j]='\0';
   
      //如果失敗次數>=7次,輸出You lose.   
   if(lose>=7){
     printf("You lose.\n");
  break;
   }
   else
   { //這裡很重要,目前失敗還沒七次的話,趕緊檢查是否已經猜到全部的字了
     int win=1;
     for(int i=0;i<100;i++){
       if(s[i]!='\0'){
      win=0;  //如果被檢查的字串裡還有剩餘沒猜到的字,win設為0
      break;
    }
     }
     if(win==1){ //如果都檢查到了,win=1,輸出You win.
    printf("You win.\n");
    break;
  }
   }
 }
 
 //判斷最後的狀況,有剩字沒檢查且lose次數<7,輸出You chickened out.
 for(int i=0;i<100;i++){
   if(s[i]!='\0'&&lose<7){
  printf("You chickened out.\n");
  break;
   }
 }
 
    //重新初始化陣列
 for(int i=0;i<100;i++){
   c[i]='\0';
   s[i]='\0';
 }
  }
  return 0;
} 

[UVa] 445 - Marvelous Mazes

#include <stdio.h>
#include <string.h>
int main(){
  char input;
  int count=0;
  while(1){
    input = getc(stdin);
    if(input==EOF)break;
 if(input>=48&&input<=57)count += input-48; //0~9
 else if(input=='!'||input=='\n')printf("\n"); //換行
 else
   while(count>0){  //根據先前累積的總和來決定輸出次數
     if(input=='b')printf(" "); //如果是b輸出空白
   else printf("%c",input);  //輸出原字元
  count--; 
   }
  }
} 

2014年8月29日星期五

[UVa] 490 - Rotating Sentences


#include <stdio.h>
#include <string.h>
char c[100][100];
char input;
int main(){
  //初始化陣列
  for(int j=0;j<100;j++)
    for(int i=0;i<100;i++)
      c[i][j]='\0';
  
  //i為橫向,j為縱向,從右上角開始
  int i=99,j=0;  
  while(1){
    input = getc(stdin);
 if(input==EOF)break;
 if(input=='\n'){ //遇換行則從前一行的最上面開始
   j=0;
   i--;
 }else{
   c[i][j] = input;
      j++; //不斷往下寫入
 }
    //if(input)break;
  }
  i++;
  int flag=i; //設定旗標,標在倒數第i行,輸出都從這邊開始往右
  int check=0;
  for(j=0;j<100;j++){
    while(i<100){
   if(c[i][j]!='\0')printf("%c",c[i][j]);
   else printf(" ");
   i++;
   if(c[i][j+1]!='\0'){check=1;} //順便檢查下一行
 }
 //如果下一行還存有資料,輸出換行,否則就跳出迴圈
 if(check==1)printf("\n");else break; 
 check=0;
 i = flag; //輸出完一列,就要將i跳回旗標開始處
  }
  return 0;
} 

[UVa] 414 - Machined Surfaces


#include <stdio.h>
#include <string.h>
char c[30]={'\0'};
int s[14];

int main(){
  int n,count=0,i,j,max=0;
  for(i=0;i<14;i++)s[i]=0; //初始化
  n=1;
  while(n!=0){
    scanf("%d",&n);  //輸入row數
 if(n==0)break;
 getchar();  //避免scanf的enter被讀入
 for(i=0;i<n;i++){
   count=0;
   for(j=0;j<30;j++)c[j]=' ';
   fgets(c,sizeof(c),stdin);
   for(j=0;j<sizeof(c);j++){
  if(c[j]=='X')count++;  //每一次讀入一行,就總X數++
   }
   s[i]=count; //把每一列的X數都存起來
   if(count>max)max=count; //取得每一列的X數最大值
 }
 /*
 for(i=0;i<n;i++){printf("%d ",s[i]);}
 printf("\n");
 */
 int total=0;
 for(i=0;i<n;i++){
   total+=max-s[i];  //total計算最多X列的X數量和其他每一列的差加總
 }
 printf("%d\n",total);
 max=0;
  }
  
} 

2014年8月28日星期四

[UVa] 494 - Kindergarten Counting Game



#include <stdio.h>
#include <string.h>
#include <ctype.h>
char c[1000]={'\0'};
int i;
int main(){
  while(fgets(c,sizeof(c),stdin)){
    int count=0;
 for(i=0;i<=strlen(c);i++){
   if(isalpha(c[i]) && !isalpha(c[i+1]))count++;
 }
 printf("%d\n",count);
  }
  return 0;
} 

2014年8月27日星期三

[UVa] 458 - The Decoder

#include <stdio.h>
#include <string.h>
char c[1000]={'\0'};
int main(){
   while(fgets(c,sizeof(c),stdin)){
     for(int i=0;i<strlen(c)-1;i++){
    printf("%c",c[i]-7);
  }
  printf("\n");
   }
}

[UVa] 10300 - Ecological Premium


乘上第一個數和第三個數,在加總即可

動物的數量會先被除掉再乘回來


#include <stdio.h>
int n,f;
int main(){
  while(scanf("%d",&n)!=EOF){
      for(int i=0;i<n;i++){
        int count=0;
        scanf("%d",&f);
        while(f>0){
          f--;
          int a,b,c;
          scanf("%d %d %d",&a,&b,&c);
          count += a*c;
        }
        printf("%d\n",count);
      }
  }
}

2014年8月26日星期二

[UVa] 264 - Count on Cantor


一開始用數學方法推斷得出,設輸入為n

k為在n的前一斜線列數,故只要找到 (1+k)*k/2 < n 的最大k值,即可判定

k%2 == 1  =>  ((2*n)-(k*k)-k)/2  /  ((k*k)+(3*k)-(2*n)+4)/2
k%2 == 0  =>  ((k*k)+(3*k)-(2*n)+4)/2  /  ((2*n)-(k*k)-k)/2

其實還有更好的方法

令 s 為包含n那一斜列的總項數

偶數列由左下至右上數,故分子為 s-n+1,分母為 k - (s-n)

k % 2 == 1 => s-n+1 / k-s+n
k % 2 == 0 => k-s+n / s-n+1


#include <stdio.h>
#include <stdlib.h>
int main(){
  int k,n;
  while(scanf("%d",&n)!=EOF){
    k=1;
    for(k=1;(k*k+k)/2<n;k++);
    k--;  
    
    
    //printf("k=%d\n",k);
    if(k%2==1)printf("TERM %d IS %d/%d\n",n,((2*n)-(k*k)-k)/2,((k*k)+(3*k)-(2*n)+4)/2);
    if(k%2==0)printf("TERM %d IS %d/%d\n",n,((k*k)+(3*k)-(2*n)+4)/2,((2*n)-(k*k)-k)/2);
  }
  return 0;
}

2014年8月24日星期日

關於Online Judge的輸入輸出

文章出處:http://infbugs.blogspot.tw/2011/12/c_20.html
謝謝沙耶,解答了我長久以來對於 input/output 的疑惑。

C 語言入門 - 在線上批改系統練功

 

如何練習使用基本語法

  自己出個練習題試著寫寫看?寫完隨手測幾個數字發現正確無誤就好了嗎?這樣其實比較辛苦,不如我們找找網路上既有的練習題試試,說不定別人想到我們沒想到 的巧妙題目,寫完了只要上傳程式碼還能自動判斷執行效率以及正確與否,多麼方便啊!這種網站去哪找?網路上現在不少,這裡介紹個我比較熟悉,也相當常見的 網站。


UVa Online Judge

  台灣俗稱 ACM 的網站。由來是它收錄了不少 ACM ICPC 競賽的題目。詳細介紹留待之後的文章。網址如下:

http://uva.onlinejudge.org

  雖然是英文的,不過也有些好心人翻譯了不少題目出來。網址如下:

http://163.32.78.26/

  網站本身不太穩定,如果死掉了可以先用別人架的鏡像站。但是鏡像站的資料較古舊,有些比較新的翻譯可能沒更新到。但也已有相當數量的題目翻譯了。如果原網站沒問題,建議還是不要用鏡像站。以下是其中一個鏡像站:

http://w.csie.org/~b97115/luckycat/

  但是並非所有題目均有翻譯。翻譯的速度通常是跟不上寫的速度,也與各譯者擅長與不擅長有關,日後仍有必要直接閱讀英文題目。現階段主要是在這裡可以方便找 到許多難度僅有一顆星的題目。未翻譯的題目中也有許多難度僅有一顆星的程度,但是並不好找,對初學者而言更無從著手。就以目前到這篇為止,也不足以解開所 有一顆星程度的題目。文末會列出此時較適合寫的題目。

  首先我們連上 UVa 的網站,左上角登入欄的底下有個 Registre 的連結,點它。Username 是你的帳號,而 Name 是你的名字。如果你沒有使用過它的舊網站,也沒印象持有舊網站 ID 的話,在 Online Judge ID 填上 00000,否則填上舊網站 ID 則可以把舊帳號整合過來。Results Email 則可以自行選擇勾或不勾。勾的話你之後有上傳題目,它會把結果寄到你的信箱。沒有勾的話也能在網站上看到結果,所以不影響。如果不嫌它很煩的話建議是勾一 下,好處是它若發現某道題目需要重新判定大家上傳的程式碼正確與否 (通常是測試不夠嚴謹以致於錯誤的程式碼被判成正確) 的話,在收信時會發現。

  之後請到信箱收認證信,收到後就完成註冊了。接下來在 UVa 登入後,就可以上傳你的程式碼了。請注意如果勾選 Remember me 再登入的話,以後有可能導致沒辦法連上。如果遇到這種情形,請開啟 Chrome 的無痕瀏覽,或 Firefox 的私密瀏覽試試,或是把瀏覽器的 cookie 清掉。

  目前能解的題目,有以下幾題:

10071
10300
11172
100
488

  未列出不代表不能解,這裡只是列出可解的幾道題。但是在開始寫之前,有幾個地方需要特別注意。

  這篇文章放在這個順位,理應存在相當多目前難以說明的東西,硬要作說明則會出現不少新東西要記,也有許多很難講明白的地方。這裡已經盡量講得淺白易懂,若一時記不完可以先大致看過,等到寫一寫出問題再回來查。


征服 UVa 的行前準備:了解線上批改系統

  首先我們必須了解它的基本規則。這類網站人稱 Online Judge,多譯作「線上批改系統」或類似的詞。通常會置有許多題目供人練習,題目會給詳盡的敘述,讓你知道你必須寫出具備什麼功能的程式。你的程式必須 能夠接受題目所規定的指定格式的輸入,依題目指定的格式輸出結果。通常會有幾組作為範例的輸出輸入供參考,也可用作測試程式是否正常運行,且給出預期答 案。

  線上批改系統之所以有「批改」二字,是因為你可以將你的程式碼上傳到該網站,它會為你測試你的程式。但是程式是無法判斷程式對錯的,又不可能進行人工檢 測。因此,最常見的方法是,準備一定數量的測試用數據,稱為「測試數據」,又稱「測試資料」或簡稱「測資」,將你的程式編譯並執行後,餵入測試數據,看你 的程式能否在可允許的時間內,產生正確的結果。

  線上批改系統會測試你的程式是否能正常編譯,運行過程有無不正常結束 (也就是當掉) 以及能否在時間內,對於給定的測試數據,將結果計算完畢並輸出。最後,如果前面都通過了,就會檢查你的結果是否正確。結果如下表:

Accepted (AC) - 測試結果正確。
Presentation Error (PE) - 測試結果正確,但格式上稍有不符。
Wrong Answer (WA) - 測試結果不正確,缺漏或夾雜不相干的輸出,或格式嚴重不符。
Time Limit Exceeded (TLE) - 程式無法在允許的時間內完成計算。通常是沒寫法,也可能是方法不夠有效率。
Run-Time Error (RE) - 程式不正常結束。通常是當掉,像除以 0 或是拜訪不該拜訪的記憶體位址。
Compilation Error (CE) - 編譯錯誤。可能選錯語言,傳錯檔案,複製不完全,或你的程式碼根本有問題。

  它餵入測試數據的方法是,執行你的程式,將存放測試數據的檔案導入至輸入中,並將你所有的輸出導出至檔案,再對該檔案進行核對。

  大部份題目會有「多重輸入」。大致有三種形式,題目都會詳述。一種是會在一開始輸入一個數字,代表接下來你必須處理多少組輸入,這種相當容易,先讀完第一 個數字就知道有幾組了。第二種是當特定的輸入出現,比如說輸入物品數是 0 或是 -1 的時候,代表的是輸入已結束。第三種較特別,就是它不會告訴你。你必須自行判斷輸入是否已結束。由於檔案不論再大,都一定有固定的大小。在讀到檔案尾的時 候,scanf() 或其它讀入用的函數,會告訴你已經到檔案尾了。scanf() 是透過回傳 EOF (即 End-of-File) 來告訴你。所以我們可以寫成這樣:

while(scanf("%d", &n) != EOF)
{
}

  來做反覆的輸入。while 你可以將它看作是沒有 A 和 C 區段的 for。這樣一來,如果輸入還不是 EOF 就會繼續執行程式。若要在程式執行中手動模擬輸入結束,可以輸入 CTRL+Z。按了之後會顯示 ^Z,按下 ENTER 就相當於遇到 EOF 了。

  輸出是否正確,是在程式結束後,才進行判斷,因此留待最後一次輸出,和每讀入一組,便處理後輸出一組,最後得出的結果會完全相同。由於只看輸出,所以你在手動輸入時打入的東西,會確實出現在畫面上,實際上不存在最後的輸出結果中,這點也要注意。

  千萬不要輸出任何關於提示輸入的文字,或其它訊息。例如「please enter a number」之類的絕對不要。這夾雜在輸出中只會被認為你的輸出結果是錯誤的。

  請務必留意換行問題。每一行的「結束」之時,請一律輸出「\n」。這符號雖被稱為「換行符號」,實質的意義卻不是告知「我們需要新的一行」,而是宣告「目前這一行結束了」。請在每一行的結束之時確實輸出「\n」而不要只在需要新的一行時才輸出。

  請務必詳讀題目在輸出格式中,關於「空白行」的敘述。空白行即是什麼都沒有的一行。若是一行之中完全沒有任何東西,直接遇上「\n」的話,就代表它是個空白行。

  通常有以下幾種情形,一種是沒特別要求,這種別輸出多餘空白行即可。要是好心怕批改時搞混而每組之間多輸出一行空白行,也會被認定是錯誤。一種是每組數據 「之後」空一個空白行。這意味著最後一組數據「之後」也要空一個空白行,所以一律多空一行即可。一種是每組數據「之間」空一個空白行,這比較麻煩。像是以 EOF 結束輸入的情形,我們不會知道有沒有下一組,所以不能隨意多輸出空白行。幸運的是,我們可以判斷這是不是第一組數據,如果不是的話,在輸出這組結果之前先 輸出一個空白行即可。

  判斷方法相當容易。我們用個變數記錄現在是不是第一組數據。一開始還沒輸入時預先設定為「是」,在第一組處理完之後,將這個變數改為「不是」。至於如何使 用變數記錄「是」與「不是」,我們可以用 0 或 1 代表。C 語言中 0 即代表「不是」,1 代表「是」。這樣我們就能夠判斷目前是不是第一組。

int first;
first = 1;
while(scanf("%d", &n) != EOF)
{
    ....
    if(first != 1)
    {
        ....
    }
    first = 0;
}

  如此一來,在第一組時 first 的值會是 1。第二組開始就會是 0。

  如果空白行多了或少了,幾乎都會被判成 Wrong Answer。在得到 WA 的結果時,不妨先檢查看看換行是否正確。

  當輸出要求在一行中輸出多個數字並以空白隔開時,請詳細按照敘述去做,別空太多格或是完全不空格,也別在一開始或最後一個數字之後,輸出空格。雖然最後一個空白是看不到的,但它實際存在,批改系統是能夠判斷出來的。

  請不要在程式中保留 while(1); 之類的程式碼。前面說過這方便我們觀察程式輸出結果,因為它「會讓程式無法自行結束」。前面提到有一種錯誤是「在允許的時間內無法處理完所有數據,輸出結 果並結束程式」,也就是 TLE,如果放了 while(1); 且執行到了的話肯定是「無法在允許時間內結束程式」,因為它根本不可能「自行結束」。我們知道處理完了,所以看完結果後會手動結束它,但是批改系統可不知 道。它可是一板一眼不知變通的。

  儘管我們學習的是 C 語言,但目前上傳時,最好在語言部份選擇 C++。UVa 上面使用的是 ANSI C,這版本的編譯器相當嚴格,容易出現編譯錯誤。

  這樣一來,我們對批改系統有了初步的認識,也擁有了解決批改系統上的基本題的能力。雖然我們連程式的基本語法都還沒有學全,但從此時開始練習,有助於增進 對這些基本語法中的基本更加了解與熟練,之後學習其它語法會更加輕鬆,也能更快上手。語法是累積的,而不是分開單獨存在的,從根本開始練習有助於學習更進 一步的東西。

  請記得保留你每一題的程式碼。若是使用公用電腦,可以使用 E-mail 夾帶程式碼的檔案,寄給自己。未來會有諸多好處。程式碼通常也不大,就算完成了數千道題,每題都寫到檔案大小 10K (這需要 10240 個字) 也不到 100MB。一部小說通常也不到 10 MB以上的,不用擔心硬碟沒地方放遊戲或其它東西。定期把執行檔清理掉即可,留著程式碼的話執行檔要生幾份有幾份。

  保留程式碼的用意並非要你用在相似題上。請紮紮實實地從頭完成你的每一道題目,而不要剪剪貼貼的,自己思考整個程式的架構與方法,並自己親手打上每一個 字。這對於寫程式的經驗絕對是有益無害的。你會對語法更加了解,對程式的運作以及之後學到的每個方法更加熟悉,儘管這比較花時間。

  即使請教他人也不要流於抄襲,在聽完高人指點與精闢分析之後,試著自己從頭思考一遍,親手實作一次,盡量不要參閱程式碼。程式碼建議在解決之後再作參考, 看看是否有更好的寫法。在自己親手實作前便參考的話,容易受制於殘存的印象,而只是試著「重現」,並非自行思考每一步的意義並寫出來。這樣會比較辛苦,但 是完成後會直接刻在內心,日後更能運用自如。

  題目也不要寫過就算了,之後想到或知道更好的做法,或是有別的想法,都可以多寫幾次試試看。題數也並非絕對重要,要在寫的過程慢慢累積經驗,多嘗試多學習。能從寫題目中獲得多少才是最重要的。 

[UVa] 642 - Word Amalgamation

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//字元比較
int n,m;
char word[2000][10], sorted[2000][10], scramble[2000][10], sorted2[2000][10];
int cmp_char(const void* _a, const void* _b){
  char* a = (char*)_a;
  char* b = (char*)_b;
  return *a-*b;
}
//字串比較
int cmp_string(const void* _a, const void* _b){
  char* a = (char*)_a;
  char* b = (char*)_b;
  return strcmp(a,b);
}
int main(){
  n = 0;
  
  //輸入字典單字,將每個單字存入word[n]中
  for(;;){
    scanf("%s", word[n]); //會自動以空白分隔單字
 if(word[n][0]=='X'&&word[n][1]=='X'&&word[n][2]=='X'&&word[n][3]=='X'&&word[n][4]=='X'&&word[n][5]=='X')break;
 n++;
  }
  //題目的OUTPUT中有敘述,輸出要按字典排序,故此排序為必要
  qsort(word, n, sizeof(word[0]), cmp_string);  //幫所有單字排序(由小到大),引入cmp_string為qsort必要之參照
  for(int i = 0; i<n; i++){
    strcpy(sorted[i], word[i]);
 qsort(sorted[i], strlen(sorted[i]), sizeof(char), cmp_char); //幫每個單字的字母各自排序 
  }
  
  //輸入欲檢查之單字
  char s[10];  
  while(scanf("%s", s)!=EOF && s[0]!='X') {  
    qsort(s, strlen(s), sizeof(char), cmp_char);  //將其內的字母做排序
    int found = 0;    
    for(int i = 0; i < n; i++){  
      if(strcmp(sorted[i], s) == 0) {  
        found = 1;  
        printf("%s\n", word[i]);  
      }  
    }  
    if(!found) printf("NOT A VALID WORD\n");  
    printf("******\n");  
  }  
  return 0;
} 

2014年8月22日星期五

[UVa] 10082 - WERTYU

參考並引用了下列連結的說明:http://www.cnblogs.com/oomusou/archive/2007/03/04/663234.html

char s[] = "Hello World";

上述的s是個char array,含12個byte(包含結尾\0),"Hello World"對s來說是initializer,將字元一個一個地copy進s陣列。
char *s = "Hello World";
上述的s是一個pointer指向char,由於"Hello World"本身就是一個string literal,所以s指向"Hello World"這個string literal的起始記憶體位置。

char s[]為陣列,雖然s = &s[0],但s是『常數』,恆等於&s[0]無法改變,但char *s為pointer,指向s[0],但卻是變數,可以任意改變,故可用*s++任意更改pointer值。


#include <stdio.h>
#include <string.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;
}

2014年8月18日星期一

[UVa] 11530 - SMS Typing

/*
  要注意,Judge測試的Case數很大
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int i,j,cases=0,count=0;
int main(){
  scanf("%d",&cases);
  char c[1000]={'\0'};
  getchar();
  for(i=0;i<cases;i++){
    fgets(c,sizeof(c),stdin);
    count=0;
    for(j=0;j<sizeof(c);j++){
      if(c[j]=='a' || c[j]=='d' || c[j]=='g' || c[j]=='j' || c[j]=='m' || 
         c[j]=='p' || c[j]=='t' || c[j]=='w' || c[j]==' ')count++;
      if(c[j]=='b' || c[j]=='e' || c[j]=='h' || c[j]=='k' ||
         c[j]=='n' || c[j]=='q' || c[j]=='u' || c[j]=='x')count+=2;
      if(c[j]=='c' || c[j]=='f' || c[j]=='i' || c[j]=='l' ||
         c[j]=='o' || c[j]=='r' || c[j]=='v' || c[j]=='y')count+=3;
      if(c[j]=='s' || c[j]=='z')count+=4;
    }
    printf("Case #%d: %d\n",i+1,count);
    for(j=0;j<1000;j++)c[j]='\0'; /*renew the array!*/
  }
  /*
  for(i=0;i<cases;i++){
    printf("Case #%d: %d\n",i+1,s[i]);
  }
  */
  return 0;
}

2014年8月14日星期四

[UVa] 10038 - Jolly Jumpers


 
宣告check[3001]陣列的用意是,兩者先減後得到的絕對差值x,
於check[x]放入1,如此只要檢查每個check陣列的元素是否為1,
即可確認所有差值是否為1至n-1了!
 
#include <stdio.h>
#include <stdlib.h>
int n;
int main(){
   while(scanf("%d",&n)!=EOF){
      int i,t=1;
   int s[3001]={0},check[3001]={0};
   for(i=1;i<=n;i++){
      scanf("%d", &s[i]);
   }
   for(i=1;i<=n-1;i++){
      check[abs(s[i+1]-s[i])]=1;  
   }
   for(i=1;i<=n-1;i++){
      if(check[i]==0)t=0;
   }
   if(t==0)printf("Not jolly\n");
   if(t==1)printf("Jolly\n");
   
   }
   return 0;
}
 

2014年8月13日星期三

[POJ] 2386 - Lack Counting

USACO 2004 November

#include <stdio.h>
int N, M;
char field[105][105]; /*宣告庭院*/
void dfs(int x, int y){
    field[x][y] = '.';
    int dx,dy,nx,ny; /*必須在裡面宣告?*/
    for(dx = -1; dx<=1; ++dx){
        for(dy = -1; dy<=1; ++dy){
            nx = x+dx;
            ny = y+dy;
            if(nx>=0 && nx < N && ny>=0  && ny<M && field[nx][ny] == 'W')
                dfs(nx, ny); /*判斷nx及ny是否在庭院,且判斷是否為積水*/
        }
    }
    return ;
}
int main(){
    while(scanf("%d%d", &N, &M)!=EOF){
        int i,j;
        for(i=0; i<N; ++i)
            scanf("%s",&field[i]);   
        int res = 0;
        for(i=0; i<N; ++i){
            for(j=0; j<M; j++){
                if(field[i][j] == 'W'){
                    dfs(i,j);
                    res++;
                }
            }
        }
        printf("%d\n", res);
    }
}