2009年6月26日 星期五

休息時間....程式寫累了就該休息一下~~

2009年6月17日 星期三

知識+ 魔方陣之顯示方向

//===============================================================
// 20090617 知識 +
// http://tw.knowledge.yahoo.com/question/question?qid=1509061704372
// 發問者 : 匿名
//===============================================================


#include <iostream>
#include <iomanip>
using namespace std;

const int N=7;

#define DISPLAY(A,B,C,D) cout<<endl<<(A)<<endl;for(B){for(C)cout<<setw(4)<<(D);cout<<endl;}

int main(void)
{
int i, j, n;
int s[N+1][N+1] = {0};
for(i=0, j=(N+1)/2, n=1; n<=N*N; s[i][j]=n++)
{
if ((n%N)==1) i++;
else
{
if (--i==0) i=N;
if (++j>N) j=1;
}
}
for(i=1;i<=N;i++) { s[0][i]=s[1][i]; s[i][0]=s[i][1]; }

DISPLAY("*上右上:", i=1;i<=N;i++, j=1;j<=N;j++, s[i][j] )
DISPLAY("*上右下:", i=0;i!=1;i=(i)?i-1:N, j=1;j<=N;j++, s[i][j] )
DISPLAY("*上左上:", i=1;i<=N;i++, j=N;j>=1;j--, s[i][j] )
DISPLAY("*上左下:", i=0;i!=1;i=(i)?i-1:N, j=N;j>=1;j--, s[i][j] )

DISPLAY("*下右上:", i=2;i!=1;i=(i==N)?0:i+1, j=1;j<=N;j++, s[i][j] )
DISPLAY("*下右下:", i=N;i>=1;i--, j=1;j<=N;j++, s[i][j] )
DISPLAY("*下左上:", i=2;i!=1;i=(i==N)?0:i+1, j=N;j>=1;j--, s[i][j] )
DISPLAY("*下左下:", i=N;i>=1;i--, j=N;j>=1;j--, s[i][j] )

DISPLAY("*左右上:", i=N;i>=1;i--, j=0;j!=1;j=(j)?j-1:N, s[j][i] )
DISPLAY("*左右下:", i=1;i<=N;i++, j=0;j!=1;j=(j)?j-1:N, s[j][i] )
DISPLAY("*左左上:", i=N;i>=1;i--, j=1;j<=N;j++, s[j][i] )
DISPLAY("*左左下:", i=1;i<=N;i++, j=1;j<=N;j++, s[j][i] )

DISPLAY("*右右上:", i=N;i>=1;i--, j=N;j>=1;j--, s[j][i] )
DISPLAY("*右右下:", i=1;i<=N;i++, j=N;j>=1;j--, s[j][i] )
DISPLAY("*右左上:", i=N;i>=1;i--, j=2;j!=1;j=(j==N)?0:j+1, s[j][i] )
DISPLAY("*右左下:", i=1;i<=N;i++, j=2;j!=1;j=(j==N)?0:j+1, s[j][i] )

return 0;
}
//================================



. "上右上"-- 數字1在[上]端, 隨後數字往[右上]方遞增; 其餘類推~~~

2009年6月16日 星期二

知識+ 位元陣列轉換

//===============================================================
// 20090616 知識 +
// http://tw.knowledge.yahoo.com/question/question?qid=1509061603511
// 發問者 :(pplgo ) http://tw.knowledge.yahoo.com/my/my?show=AD01409480
//===============================================================

這還是一個小程式, 是做位元陣列轉換的, 題目是將8bits的陣列, 轉換為5bits的陣列,
我寫了一種方法; 而東大也寫了一種方法, 因有參考價值所以一併收錄...



#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// ADing法轉換 -------
unsigned char * BitsConvert(int bits, unsigned char *A, int *size)
{
if (bits<1 || bits>8 || A==NULL || *size<1) return NULL;
int i, a, b, s[8], len=*size;
*size = (*size*8+bits-1)/bits;
unsigned char * B = (unsigned char *) malloc(*size);
unsigned char m = 0xFF>>(8-bits);
for(b=0, i=8-bits; b<8; ++b, i=(i<=0)?i+8-bits: i-bits)
s[b]=i;
for(b=0; b<*size; ++b)
{
i=s[b%8];
a=b*bits/8;
if (i>=0) B[b] = (A[a]>>i)&m;
else if(a+1>=len) B[b] = (A[a]<<-i)&m;
else B[b] = ((A[a]<<-i)|(A[a+1]>>(8+i)))&m;
}
return B;
}
// 東大法轉換 --------
unsigned char * BitsTransfer(int bits, unsigned char *A, int *size)
{
if (bits<1 || bits>8 || A==NULL || *size<1) return NULL;
int i, j, a, b, d, len=*size;
*size = (*size*8+bits-1)/bits;
unsigned char * B = (unsigned char *) malloc(*size);
unsigned char m = 0x80;
for(a=b=d=j=0; a<len; ++a)
{
for(i=0; i<8; ++i)
{
d = (d<<1) + ((A[a]&m)? 1: 0);
if((m>>=1)==0) m=0x80;
if(++j==bits)
{
B[b++]=d;
d=j=0;
}
}
}
if (j) B[b++]=d<<(bits-j);
return B;
}
//==================================
const int MAX = 32; // 資料量
const int BIT = 5; // 擷取bit數

// --- 資料顯示
void DisplayData( char *Msg, unsigned char *data, int len)
{
int i;
printf(Msg, len);
for(i=0; i<len; )
{
printf("%02X ", data[i]);
if(++i%20==0 || i==len) printf("\n ");
}
}

// 主程式 =======
int main()
{
unsigned char *a;
int i, len;
unsigned char *b;
double runC, runT;
clock_t startC, startT;

a = (unsigned char *)malloc(MAX);
srand((unsigned)time(NULL));
for(i=0; i<MAX; i++)
a[i] = (unsigned char)(rand()%0x100);
DisplayData("顯示原始資料, 共%d筆:\n ", a, MAX);

//-------------------------- BitsConvert()
startC = clock();
len = MAX;
b = BitsConvert(BIT, a, &len);
runC = (double)(clock()-startC)*1000/CLOCKS_PER_SEC;
if (b!=NULL)
{
DisplayData("\n顯示用 BitsConvert()處理後的資料, 共%d筆:\n ", b, len);
free(b);
}
printf("\n* BitsConvert() 的處理時間為 %.2fms\n\n", runC);
//--------------------------

//-------------------------- BitsTransfer()
startT = clock();
len = MAX;
b = BitsTransfer(BIT, a, &len);
runT = (double)(clock()-startT)*1000/CLOCKS_PER_SEC;
if (b!=NULL)
{
DisplayData("\n顯示用 BitsConvert()處理後的資料, 共%d筆:\n ", b, len);
free(b);
}
printf("\n* BitsTransfer() 的處理時間為 %.2fms\n\n", runT);
//--------------------------

free(a);
return 0;
}
//==============================================

2009年6月15日 星期一

知識+ 小程式 -- 這樣的數有幾個?

題目是: 這樣的數有幾個?

說明:若有一個小於100000的整數,它加上100後是一個完全平方數,再加上168又是一個完全平方數,請利用程式求出符合這個條件的數有幾個,並將之輸出。

//===============================================================
// 這題在 知識 + 出現了好幾次...
// http://tw.knowledge.yahoo.com/question/question?qid=1609061408255
// http://tw.knowledge.yahoo.com/question/question?qid=1009060305235
// http://tw.knowledge.yahoo.com/question/question?qid=1009061311160
// http://tw.knowledge.yahoo.com/question/question?qid=1509052404945
//===============================================================

這題很簡單, 但是有兩個陷阱...
1) 小於100000的整數 <=== 並非只限定正整數
2) 再加上168又是一個完全平方數 <=== 是加上100後再加168

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

int main()
{
double d;
int i, count=0;

printf("在小於100000的整數中,有 ");
for (i=-100; i<100000; i++)
if ((d=sqrt(i+100.), d==(int)d) && (d=sqrt(i+268.), d==(int)d) && ++count )
printf("%d, ", i);
printf("等共有 %d 個整數符合此條件。\n", count);

return 0;
}


.

倘若程式要求先印出所得數量, 再印出符合條件的整數時, 可用陣列先存放, 問題是要宣告或配置多大的陣列來存放呢? 一是先宣告至少為安全數量(需不小)的陣列. 二是運算兩次, 第一次運算取得總數量後再配置陣列大小來供第二次運算存放. 除此之外呢? 可使用遞迴...
.

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

int count=0;

int check(int num)
{
int i;
double d;
for(i=num-1; i>=-100; i--)
if ((d=sqrt(i+100.), d==(int)d) && (d=sqrt(i+268.), d==(int)d) ) break;
if (i<-100)
printf("在小於100000的整數中,共有 %d 個整數符合此條件;分別是: ", count);
else printf("%d%c ", check(i), (count++)? ',': ' ' );
return num;
}

int main()
{
check( 100000);
return 0;
}

兩天天數差 與 週數計算

//===============================================================
// 20090614 知識 +
// http://tw.knowledge.yahoo.com/question/question?qid=1609061406632
// 發問者 :(↙小貓頭﹌MOMO↗ ) http://tw.knowledge.yahoo.com/my/my?show=AD01407519
//===============================================================

這是小程式, 所以就分別用 C 和 C++ 寫了一次; 要注意得是 fflush(stdin) 在C++中是無法清除錯誤輸入的, 所以在C++就用了其它的方法來處理... 而若程式有需要考慮編譯的相容性時, 一般是建議不要使用未有標準定義的fflush(stdin) .

(A) C 程式

#include <stdio.h>
#include <stdlib.h>

// 取得天數(回傳值), 並回傳星期幾(*week) 與 當年第幾週(*yw)
int GetDays(int year, int month, int day, int *week, int *yw )
{
int m[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if ((year%4==0 && year%100!=0) || year%400==0) m[1]=29; // 閏年2月
if (year<1 || month<1 || month>12 || day<1 || day>m[month-1]) return -1;
int y = year-1;
int d = y*365+y/4-y/100+y/400; // d: 年前總天數
int i, dy=day;
for(i=0; i<month-1; i++) dy+= m[i]; // dy: 當年天數
*week = (d+dy)%7; // 星期
*yw = (dy+d%7)/7+1; // 第幾週
return (d+dy); // 統計天數
}
// 主程式 ====
int main()
{
char *week[]= { "日", "一", "二", "三", "四", "五", "六" };
int y1, m1, d1, da1, w1, yw1;
int y2, m2, d2, da2, w2, yw2;
while(!fflush(stdin))
{
printf( "請輸入第一個日期(西元年﹑月﹑日,請以空白相隔): ");
if (scanf("%d %d %d", &y1, &m1, &d1)==3 &&
(da1 = GetDays(y1, m1, d1, &w1, &yw1))>0) break;
printf( "日期輸入錯誤!!\n重新");
}
while(!fflush(stdin))
{
printf( "請輸入第二個日期(西元年﹑月﹑日,請以空白相隔): ");
if (scanf("%d %d %d", &y2, &m2, &d2)==3 &&
(da2 = GetDays(y2, m2, d2, &w2, &yw2))>0) break;
printf( "日期輸入錯誤!!\n重新");
}
int days = (da1>da2)? da1-da2: da2-da1; // 計算兩天所差天數
printf( "\n第一個日期為 星期%s 為當年的第 %d週", week[w1], yw1);
printf( "\n第二個日期為 星期%s 為當年的第 %d週", week[w2], yw2);
printf ( "\n兩個日期相差 %d天 間隔 %d週", days, days/7 );
if (days%7==0) printf( "整\n\n");
else printf ("又 %d天\n\n", days%7);

system("pause"); // 暫停
return 0;
}
//==============================================================


(B) C++ 程式

#include <iostream>
#include <limits> // 為了用 numeric_limits (clearInput函式用)
using namespace std;

// 取得天數(回傳值), 並回傳星期幾(*week) 與 當年第幾週(*yw)
int GetDays(int year, int month, int day, int *week, int *yw )
{
int m[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if ((year%4==0 && year%100!=0) || year%400==0) m[1]=29; // 閏年2月
if (year<1 || month<1 || month>12 || day<1 || day>m[month-1]) return -1;
int y = year-1;
int d = y*365+y/4-y/100+y/400; // d: 年前總天數
int dy=day;
for(int i=0; i<month-1; i++) dy+= m[i]; // dy: 當年天數
*week = (d+dy)%7; // 星期
*yw = (dy+d%7)/7+1; // 第幾週
return (d+dy); // 統計天數
}
// 淨空錯誤輸入 ---
void clearInput()
{
cin.clear();
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
}
// 主程式 ====
int main()
{
char *week[]= { "日", "一", "二", "三", "四", "五", "六" };
int y1, m1, d1, da1, w1, yw1;
int y2, m2, d2, da2, w2, yw2;
for(y1=m1=d1=0; true; clearInput(), y1=m1=d1=0)
{
cout<< "請輸入第一個日期(西元年﹑月﹑日,請以空白相隔): ";
cin >> y1 >> m1 >> d1;
if ((da1 = GetDays(y1, m1, d1, &w1, &yw1))>0) break;
cout<< "日期輸入錯誤!!"<< endl << "重新";
}
for(y2=m2=d2=0; true; clearInput(), y2=m2=d2=0)
{
cout<< "請輸入第二個日期(西元年﹑月﹑日,請以空白相隔): ";
cin >> y2 >> m2 >> d2;
if ((da2 = GetDays(y2, m2, d2, &w2, &yw2))>0) break;
cout<< "日期輸入錯誤!!"<< endl << "重新";
}
int days = (da1>da2)? da1-da2: da2-da1; // 計算兩天所差天數
cout<< endl << "第一個日期為 星期" << week[w1] << " 為當年的第 "<< yw1 << "週";
cout<< endl << "第二個日期為 星期" << week[w2] << " 為當年的第 "<< yw2 << "週";
cout<< endl << "兩個日期相差 " << days << "天 間隔 " << (days/7) << "週";
if (days%7==0) cout<< "整" << endl << endl;
else cout<< "又 "<< (days%7) << "天" << endl << endl;

system("pause"); // 暫停
return 0;
}
//==============================================================


【執行結果】 :
請輸入第一個日期(西元年﹑月﹑日,請以空白相隔): 1980 5 10
請輸入第二個日期(西元年﹑月﹑日,請以空白相隔): 2009 6 16

第一個日期為 星期六 為當年的第 19週
第二個日期為 星期二 為當年的第 25週
兩個日期相差 10629天 間隔 1518週又 3天