亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

C程序設計例解

2019-11-17 05:20:09
字體:
來源:轉載
供稿:網友
    在程序設計過程中,類似于解決其它復雜的智力問題,我們使用推測、直覺、技巧、靈感和經驗在內的各種技巧和技術,最經常使用的工具是抽象技術。一般地,在開始階段,因還未了解問題的全部細節和求解的方法,主要問題集中于對問題的求解方案的全局作出決策,設計出大概的求解步聚,這是非常抽象的算法。其中有許多細節還不明確,只是用結構化的控制結構將若干抽象的計算步聚有機地聯系起來。在抽象的計算步聚中,只是確定了計算的目標,而所指的操作對象和數據結構通常還是未確定的。以計算目標為線索,對抽象計算步聚作進一步的深入考慮,可能會引入數據結構和操作對象,并給也更具體的計算過程的描述。其中也許依舊包含有某些抽象計算步聚,但與原來的計算步聚相比,在規模及難度上已有所降低。對新產生的抽象計算步聚作進一步的深入考慮和分解,如此循序漸近,計算步聚、操作對象和數據結構會越來越明確,抽象的東西會越來越少,直至有關細節都已確定后設計過程才算結束,隨后的工作是程序編碼。
由此看來,程序設計的開始階段最重要的就是確定算法和使用何種數據結構,只要這個過程完成得很好,隨后的程序代碼編寫工作也就會很輕松了。所以學習時要從例子中得到啟發,了解如何設計算法、設計數據結構、最終編出程序或函數的設計過程。

------------------------------------------------------------------------------------------

01. 試按以下給出的基數排序算法思想為整數鏈表編寫一個排序 函數
解:
基數排序是按表元鍵值的各位值進行排序。
設有一個整數鏈表,其中表元的鍵值為不超過三位數的整數,不妨設鍵值形式ABC。其中A表示鍵值的百位數,B為十位數,C為個位數。首先按鍵值中的個位值C對鏈表作分拆和鏈接,先把鏈表分拆成多至10個隊列鏈表,然后以C的值從0至9的順序把分拆后的十個隊列鏈表重新收集成一個鏈表。接著依次對鍵值中的B和A進行同樣的分拆和鏈接操作,則最后收集起來的鏈表是按鍵值從小到大排序鏈接的。如有一個鏈表按它們的鍵值其表元的鏈接順序依次為:
153 678 56 288 457 653 721 876 433 254
按它們的鍵值的個位分拆,得到十個隊列鏈表,列出它們的鍵值順序有:
0: 空鏈表
1: 721
2: 空鏈表
3: 153 653 433
4: 254
5: 空鏈表
6: 56 876
7: 457
8: 678 288
9: 空鏈表
順序將它們收集一起后,鏈表的鍵值順序有:
721 153 653 433 254 56 876 457 678 288
再按它們鍵值的十位分拆,得到十個隊列鏈表,列出它們的鍵值順序有:
0: 空鏈表
1: 空鏈表
2: 721
3: 433
4: 空鏈表
5: 153 653 254 56 457
6: 空鏈表
7: 876 678
8: 288
9: 空鏈表
順序將它們收集在一起后,鏈表的鍵值順序有:
721 433 153 653 254 56 457 876 678 288
再按它們鍵值的百位分拆,得到十個隊列鏈表,列出它們的鍵值順序有:
0: 56
1: 153
2: 254 288
3: 空鏈表
4: 433 457
5: 軍分區邊表
6: 653 678
7: 721
8: 876
9: 空鏈表
順序將它們收集一起后,鏈表的鍵值順序有:
56 153 254 288 433 457 653 678 721 876
這是一個按鍵值從小到大鏈接的鏈表。
基數排序主要包含以下控制過程,主循環控制對鍵值順序從低位高位的重復操作,在主循環內包含兩個計算步聚:按鍵值的當前位置分拆鏈表為十個隊列鏈表,將對應0至9的十個隊列鏈表收集成一個鏈表。用算法形式描述其計算過程如下:
算法--基數排序
{
依次對鍵值的個位到高位逐位循環
{
按鍵值的當前位將鏈表分拆成十個隊列鏈表;
按對應0至9的順序將十個鏈表收集成一個鏈表;
}
}
由于分拆時,當前表元接在對應值的隊列鏈表的末尾,為了便于為每 個隊列鏈表接入新表元,除每個隊列鏈表有首指針外,還應為每個隊列鏈表引入末表元指針。又為了能方便處理十個隊列,十個隊旬的頭和尾指針又分別構成兩個指針數組。按對應值0至9 的順序將十個鏈表收集成一個鏈表的工作只要將空鏈表除外,順序將這些鏈表的首尾鏈接即可。另外,編寫函數需要知道鏈表的首指針,但排序后鏈表中各表元的鏈接順序會改變,原來的首表元可能不再是首表元,即鏈表的首指針也會改變,所以函數的參數應為鏈表首指針的指針。
程序代碼如下:
#include<stdio.h>
#include<stdlib.h>
#define KEYN 3
strUCt ele{
int key;
struct ele *link;
};
void basesort(struct ele **h)
{
int i,j,factor;
struct ele *head[10],*tail[10],*p,*u;
/*依次對鍵值的個位到高位逐位循環*/
for(i=0,factor=1,p=*h;i<KEYN;factor*=10,i++)
{
/*按鍵值的當前值將鏈表分拆成十個隊列鏈表*/
for(j=0;j<10;j++) /*預置十個空鏈表*/
head[j]=NULL;
while(p)
{ /*將*p接到某隊列鏈表*/
u=p->link; /*保護下一個表元的指針*/
j=(p->key/factor)%10; /*求表元鍵值的當前位*/
if(head[j]==NULL) /*按當前位值將*p接在對應隊列的末尾*/
head[j]=p;
else
tail[j]->link=p;
tail[j]=p;
p->link=NULL;
p=u; /*預備訪問下一表元*/
}
/*將十個隊列鏈表鏈接成一個鏈表*/
p=NULL;
for(j=0;j<10;j++)
{
if(head[j]==NULL)continue; /*跳過空鏈表*/
if(p==NULL)p=head[j];
else u->link=head[j]; /*各鏈表首尾順序鏈接*/
u=tail[j];
}
}
*h=p;
}
int a[]={35,298,832,932,38,635,22,15,48};
#define N sizeof a/sizeof a[0]
void main()
{
struct ele *h,*u;
int i;
h=NULL; /*先形成一個空鏈表*/
for(i=0;i<N;i++)
{ /*任意形成一個鏈表*/
u=(struct ele *)malloc(sizeof(struct ele));
u->key=a[i];
u->link=h;
h=u;
}
basesort(&h); /*排序*/
for(u=h;u;u=u->link) /*順序輸出鏈表各表元的鏈值*/
printf("/n");
}

程序運行結果為:
15 22 35 38 48 298 635 832 932

 02.找一個最小的自然數x,使它等于不同的兩對自然數的三次冪之和,即使得:
x=a*a*a+b*b*b=c*c*c+d*d*d
其中a,b,c,d都是自然數,且有a!=c和a!=d
解:
問題要找的解是兩個自然數對,以自然數對為解的候選者,如程序能這樣枚舉解的候選者,使枚舉出來的自然數對的三次冪之和構成一個不減的序列,則當發現兩個自然數對的三次冪之和相等時,這兩對自然數就是問題的解。將這種思想寫成抽象算法描述如下:
{
i1=1;j1=1;x=i1*i1*i1+j1*j1*j1;
do
{
i0=i1;j0=j1;min=x; /*保存上一個解的候選者*/
確定下一對自然數i1,j1;
x=i1*i1*i1+j1*j1*j1;
}while(x!=min);
printf("%d=%d^3+%d^3=%d^3+%d^3/n",x,i0,j0,i1,j1);
}
問題已轉化成如何按上述要求逐一自然數對。
為了尋找產生候選者規則的線索,將問題簡化為找一個最小的自然數x,使它等于不同的兩對自然數的平方之和。下面列出部分兩個自然數的平方之和的數表s[],其中:
s[i][j]=i*i+j*j
C程序設計例解(圖一)
點擊查看大圖

從上面的s[]表查得:
50=1*1+7*7=5*5+5*5
65=1*1+8*8=4*4+7*7
所以50是兩對自然 平方和的最小者。要尋找的產生候選者的規則就是要尋找一個方法,使枚舉產生的候選者(自然數對)的平方和構成以下數列:
2 5 8 10 13 ... 45 50 50
仔細考查表中s[i][j]與i和j,不難發現有以下性質:
1) s[i][j]>s[i][k],對于所有的i,當j>k
2) s[i][j]>s[k][j],對于所有的j,當i>k
3)s[i][j]=s[j][i]
因問題將自然數對(i,j)和(j,i)視為同一個自然數對,所以只需考慮i>=j的情況,性質1)說明對于表中的每一行,應從左到右逐個考查,且沒有必要保存一整行的候選者供選擇,一行只要保存一個已足夠。當某行的當前候選者已被確認不是解時,則可生成該行的下一個候選者,等候被考慮。
由以上分析,可用下面的兩個一維數組表示當前正在考慮的狀態:
int s[?],j[?];
其中?意指數組的大小還未確定。數組j[]的成份j[k]表示s表中的第k行當前待考慮的列號。所以,s[]和j[]有關系:
s[k]=k*k*k+j[k]*j[k]*j[k]
將以上分析結果反映到找解方法中,原先的找解算法可改寫成如下形式:
{
for(k=1;k<?;k++)
{ /*每行都從第一列一始考查*/
j[k]=1;
s[k]=k*k*k+1;
}
i=1; /*最初候選者在第一行*/
do
{
min=s[i];i0=i;j0=j[i];
為i行設定下一個候選者存入s[i];
在s[]中找最小的候選者為正式候選者,并將找到的位置存于i中;
}while(s[i]!=min);
printf("%d=%d^3+%d^3=%d^3+%d^3/n",min,i0,j0,i,j[i]);
}
按上述算法編寫程序還有兩處不足,需進一步確定或調整:一是為個數不確定的數組s[]和j[]送初值;另一個是個數不確定的候選者中選正式候選者。由性持,由性質2),引入當前考慮的行的范圍,最大行ih和最小行il,其中ih是指有j[k]為1的最小下標k,因為當前還不可能在ih行之后選到最小的s[i],所以置初值和選最小元可局限于k<=ih的s[k]中進行。另外,當j[i]=i時,因對s表的考查只限于它的左下角,所以對該行的進一步考查應放棄。利用這個事實,程序可引入il表示s表的當前行范圍的下界。于是置初值、尋找局限于s表的il 行到 ih行之間。每當j[i]=i時,il增1;每當j[i]=1時,ih增1,并同時設定s[ih]和j[ih]的初值。
再次把上述思想反映到算法中,找解算法又可改寫成如下形式:
算法--找一個最小的自然數x,使它等于不同的兩對自然 的三次冪之和
{
il=1;ih=1; /*首先只局限于第一行*/
j[1]=1;s[1]=2;i=1;
do
{
min=s[i];i0=i;j0=j[i];
if(j[i]==1)
{ /*調整ih,并為j[ih]與s[ih]設定初值*/
ih++;
j[ih]=1;
s[ih]=ih*ih*ih+1;
}
if(j[i]==i)il++; /*調整il*/
else
{ /*為i行設定下一個待候選者*/
j[i]++;
s[i]=i*i*i+j[i]*j[i]*j[i];
}
/*以下確定新的i,使得s[i]=min(s[il],...s[ih])*/
i=il;
for(k=il+1;k<=ih;k++)
if(s[k]<s[i])i=k;
}while(s[i]!=min(;
printf("%d=%d^3+%d^3=%d^3+%d^3/n",min,i0,j0,i,j[i]);
}
以上算法可作為最后的算法,下面的程序作了必要的優化,避免反復計算一個整數的三次冪。引入數組p[],其中p[i]存儲i*i*i。

程序代碼如下:
#include<stdio.h>
#define N 50
void main()
{
int i,il,ih,i0,j0,min,k;
int j[N],s{n],p[N];
il=1;ih=1;j[1]=1;
p[1]=1;s[1]=2;i=1;
do
{
min=s[i];i0=i;j0=j[i];
if(j[i]==1)
{
ih++;p[ih]=ih*ih*ih;
j[ih]=1;s[ih]=p[ih]+1;
}
if(j[i]==i) il++;
else{
j[i]++;
s[i]=p[i]+p[j[i>;
}
i=il;
for(k=il+1;k<=ih;k++)
if(s[k]<s[i]) i=k;
}while(s[i]!=min&&ih!=N);
if(s[i]==min)
printf("%d=%d^3+%d^3=%d^3+%d^3/n",min,i0,j0,i,j[i]);
else printf("The %d is too small./n",N);
}

程序運行結果如下:

1729=10^3+9^3=12^3+1^3

03. 找一個最小的自然數,使它等于不同的兩組三個自然數的三次冪之和,即找最小的x,使得:
x=a*a*a+b*b*b+c*c*c+d*d*d+e*e*e+f*f*f
其中,a,b,c,d,e,f都是自然數,a<=b<=c<=d<=e<=f; [a,b,c]!=[d,e,f]
解:
利用上一問題的求解思想,上一問題在正方形平面下三角區內找解,本題在正立方體的下三角棱內找解。記i為三角棱體的平面,j為某平面的行,k為某行上的列。當前考察的下三角棱體的范圍由最上平面至最下平面控制;對應每個平面的下三角區域,在每個下三角區域內當前待考查的行可由行的下界和上界控制,每個有效行上的候選列由其當前列來表示。因此有如下解法:
算法---找一個最小的自然數x,使它等于不同的兩組三個自然數的三次冪之和
{
以三角棱體的頂點為最初候選者;
為最初尋找平面設定行的變化范圍和列的初值;
do
{
保存上一個候選者;
if(當前候選者在最下平面)
{
尋找平面范圍的最下平面向下進一層;
為新平面設定行的變化范圍;
}
if(在最上平面最下角點找到候選者)
尋找平面范圍的最上平面向下進一層;
else
{
if(在第一列找到候選者)
{
當前平面的行的變化上增1;
置當前平面的最高行的列為1;
}
if(在對角線上找到候選者)
當前平在的行的變化下界增1;
else
調整當前平面當前行的列號值;
}
在當前最上平面至當前最下平面范圍內尋找最小值的候選者;
}while(兩候選者對應的值不相等);
輸出解;
}
因每個平面有行變化的下界和上界,程序分別用兩個一維數組來存貯;每個平面的每行都有一個當前列,程序用一個二維數組來存貯;為避免反復計算一個整數的三次冪,另引入一個一維數組,對應第i下標位置存貯i*i*i。令當前找到的候選者為i1,j1,k表示在i1平面的第j1行的k1列找到的候選者。因候選者限制在三角棱內,i1,j1,k1滿足條件:
i1>=j1>=k1
當候選者在最下平面時,則最下平面向下進一層,并為新平面設定行的變化范圍和對應列號;當前最上平面的最下角點找到候選者時,最上平面向下進一層;當在第一列找到候選者時,當前平面的行的上界增,并為新的行設定初始列號;當在某行的對角線上找到候選者時,該行不應該再被考慮,當前平面的行的下界增1;其它情況,當前行的下一列將會被考慮,為該行調整當前列。在調整當前平面的行的下界和上界時,應不能超過當前平面號。為在三角棱體的當前有效平面內找最小值的候選者,先假定最上平面的最小行的當前列為下一個候選者,然后自最上平面至最下平面,每個平面自最小行至最大行,尋找最小值所在平面號、行號和列號。

程序代碼如下:
#include<stdio.h>
#define N 100
void main()
{
int i,j,il,ih,i0,j0,k0,i1,j1,k1;
int jl[N],jh[N]; /*第i層平面的行的變化范圍,自jl[i]至jh[i]*/
int k[N][N]; /*第i層平面中,對應行j,當前的列號值為k[i][j]*/
int p[N], min; /*p[i]=i*i*i*/
i1=1;j1=1;k1=1; /*首先只局限下三角棱體的頂點*/
il=1;ih=1; /*預置i的變化范圍初值il<=i<=ih*/
jl[1]=1;jh[1]=1; /*對應i層平面的行的變化范圍*/
k[il][jl[il>=1; /*第i層平面中,對應行的列的初值*/
p[1]=1;
do
{
min=p[i1]+p[j1]+p[k1];
i0=i1;j0=j1;k0=k1;
if(i1==ih) /*當前候選者在ih平面,則ih增1*/
{
ih++;
p[ih]=ih*ih*ih;
/*為ih平面設定j的變化范圍和對應k值*/
jl[ih]=1;jh[ih]=1;k[ih][1]=1;
}
if(i1==il&&j1==il&&k1==il)
il++; /*在il平面最下角點找到候選者,il增1*/
else
{
if(k1==1&&jh[i1]<i1)
{ /*在第一列找到候選者,i1平面的行的上界增1*/
jh[i1]++;
k[i1][jh[i1>=1;
}
if(k1==j1&&jl[i1]<i1)
jl[i1]++; /*在對角線上找到候選者,il平面的行的下界增1*/
else
k[i1][j1]++; /*調整i1平面當前行的列號*/
}
i1=il; /*預定最上平面的最小行的當前列為下一個候選者*/
j1=jl[i1];
k1=k[i1][j1];
for(i=il;i<=ih;i++) /*尋找最小值所在平面號、行號和列號*/
{
for(j=jl[i];j<=jh[i];j++)
if(p[i]+p[j]+p[k[i][j><p[i1]+p[j1]+p[k1])
{
i1=i;j1=j;k1=k[i][j];
}
}
}while(p[i1]+p[j1]+p[k1]!=min&&ih!=N);
if(p[i1]+p[j1]+p[k1]==min)
printf("%4d=%2d^3+%d^3+%d^3=%2d^3+%d^3+%d^3/n",min,i0,j0,k0,i1,j1,k1);
else printf("The %d is too small./n",N);
}

程序運行結果如下:
251 = 5^3 + 5^3 + 1^3 = 6^3 + 3^3 + 2^3
04. 試從含有n個int型數的數組中刪去若干個成分,使剩下的全部成分構成一個不減的子序列。設計算法和編寫程序求出數組的不減子序列的長。
解:
從數組的第一個元素開始,順序考察數組的每個元素,當數組的全部元素都被考察后才能求出數組的最長不減子序列的長。設數組為b[],已考察了b[0]至b[i-1]的全部元素,求得當前最長的不減子序列長為k。當前正要考察b[i]是否會引起k值增大,依靠于b[i]是否會大于或等于b[0]至b[i-1]中某個最長不減子序列的終元素.b[0]至b[i-1]中可能有多個長為k的不減子序列。很顯然,在同樣長度的不減子序列中,只要保留那個子序列終元素最小的一個就足夠了。如有一變量保存有在b[0]至b[i-1]中長度為k的不減子序列最小的終元素,這樣在b[0]至b[i-1]中,是否有長度為k+1的不減子序列,依靠于b[i]是否大于等于那個長度為k的不減子序列的終元素值。
但當b[i]小于那個長度為k的不減子序列最小的終元素的值時,假如在b[0]至b[i-1]中有長度為k-1的不減子序列,且該子序列的值不大于b[i],這時因長度為k-1的不減子序列的終元素值小于等于b[i],就得到一個終元素更小的長度為k的不減子序列。為能發現上述可能,就得保留長度為k-1的不減子序列的終元素。依此類推,為保留長為k-2,k-3等的不減子序列,相應地也要為它們保留終元素的值。為此要引入一個數組變量,設為數組a[],其第j個元素a[j]存放長為j的不減子序列的終元素的值。顯然,數組a[]中的元素也是不減的序列。利用這個性質,在考察b[i]時,就能知道a[]中哪個元素需要改變。從最長子序列至最短子序列順序尋找終元素小于等于b[i]的長為j的子序列,因b[i]大于等于長為j的不減子序列的終元素,找到了一個終元素更小的長為j+1的不減子序列,用b[i]作長為j+1的子序列的終止元素。當j的值為k 時,已為長為k+1的子序列設定了終元素,這時最長不減子序列長k應增1。通過以上分析,得到求最長不減子序列長的算法如下:
算法---求數組b[]的最長不減子序列長
{
置最長不減子序列長k為1;
用b[0]設置長為1的子序列的終止元素;
for(i=1;i<n;i++) /*順序至b[1]考察至b[n-1]*/
{
以子序列長為k至1的順序尋找其終元素小于等于b[i]的長為j的子序列;
用b[i]作為長為j+1的子序列的終元素;
if(j==k)k++; /*最長不減子序列長k增1*/
}
}
程序代碼如下:
#include<stdio.h>
#define N 100
int b[]={9,8,5,4,3,2,7,6,8,7,5,3,4,5,9,1};
int a[N];
#define n sizeof b/sizeof b[0]
void main()
{
int k,i,j;
a[1]=b[0];
k=1;
for(i=1;i<n;i++)
{
for(j=k;j>=1&&a[j]>b[i];j--);
a[j+1]=b[i]; /*長為j+1的子序列的終元素存貯在a[j+1]*/
if(j==k) k++; /*最長不減子序列長k增1*/
}
printf("K = %d/n",k);
}

程序運行結果如下:
k = 5
------------------
若把本問題改為求從數組中刪去部分元素后的最長不減子序列,就要在求最長不減子序列長的過程中,不僅要保留各種長度不減子序列的終元素,同時要保留不減子序列的全部元素。為此,上述程序中的數組a[]應改為兩維數組a[][],其中a[][]的j行存儲長為不減子序列的元素,該子序列的終元素為a[j][j-1]。在找到一個終元素更小的長為j+1的不減子序列時,除用b[i]作為j+1的子序旬的終止元素外,應同時將長為j的子序列元素全部復制到長為j+1的子序列中。直接寫出程序如下:
#include<stdio.h>
#define N 100
int b[] = {9,8,5,4,3,2,7,6,8,7,5,3,4,5,9,1};
int a[N][N];
#define n sizeof b/sizeof b[0]
void main()
{
int k,i,j,m;
a[1][0]=b[0];
k=1;
for(i=1;i<n;i++)
{
for(j=k;j>=1&&a[j][j-1]>b[i];j--);
for(m=0;m<j;m++) /*長為j的子序列復制到長為j+1的子序列*/
a[j+1][m]=a[j][m];
a[j+1][j]=b[i]; /*長為j+1的終元素存貯在a[j+1][j]*/
if(j==k) k++; /*最長不減子序列長k增1*/
}
printf("K = %d/n",k);
for(j=0;j<k;j++)
printf("%4d",a[k][j]);
printf("/n");
}
程序運行結果如下:
k=5
2 3 4 5 9

05. 從n個不同價值、不同重量的物品中選取一部分,在不超過限定的總重量的前提下,使該部分的價值最大。這里假定的總重量不超過n個物品的總重量總和,且沒有一樣物品的重量超過限定的總重量。
解:
這個問題是求最佳解的典型例子。為找最佳解,需生成所有可能的解。在生成這些解的同時,保留一個指定意義下的當前最佳解,當發現一個更好的解時,就把這個解改為當前最佳解,并保留之。
現給出一組n個物品中找出滿足約束條件的最佳解的通例。為便于構造算法,采用遞歸方法。構成可接受解的所有選擇是通過依次考察組中的各個物品的結果,對每個物品的考察均有兩種可能:或所考察的物品被包括在當前選擇中,或所考察的物品不被包括在當前選擇中。遞歸函數是描述指定物品被包括或不被包括在當前選擇中的計算過程,只要指定物品被包括后重量滿足約束條件,該物品被包括是應該被考慮的;僅當一個物品如不被包括也可能達到比當前最佳解所達到的總價值大時,為滿足重量的限制,不把該物品包含在當前選擇中也是應該被考慮的。為此,遞歸函數設有三個參數:指定的物品、當前選擇已達到的總重量和可能達到的總價值。下面的遞歸算法就是考察某個物品在當前選擇中是否被包括的計算過程描述。
算法---物品i在當前選擇中被包括與否的遞歸算法
try(物品i,當前選擇已達到的總重量tw,可能達到的總價值tv)
{
/*考察當前選擇包含物品i的合理性*/
if(包含物品i是可接受的)
{
將物品i包括在當前解中;
if(i<n-1(try(i+1,tw+物品i的重量,tv);
else
調整當前最佳解;
將物品i從當前解中消去;
}
/*考察當前選擇不包含物品i的合理性*/
if(i<n-1)try(i+1,tw,tv-物品i的價值);
else
調整當前最佳解;
}
對當前選擇而言,“包含物品i是可接受的”準則是它被包括后,有可能達到的總價值也不小于當前最佳解所達到的價值,因為假如小于的話,繼續考察下去也不會產生更好的解。

程序代碼如下:
#include<stdio.h>
#define N 100
double limw, /*物品的約束重量*/
totv, /*全部物品的總價值*/
maxv; /*解的總價值*/
int opts[N], /*當前最佳選擇*/
cs[N]; /*當前選擇*/
int n, /*物品數*/
k; /*工作變量*/
struct{
double weight; /*物品的重量*/
double value; /*物品價值*/
}a[N]; /*一組物品*/
void tryy(int i,double tw,double tv)
{
/*考察當前選擇物品i的合理性*/
if(tw+a[i].weight<=limw) /*包含物品i是可接受的*/
{
cs[i]=1; /*將物品i包括在當前解中*/
if(i<n-1)tryy(i+1,tw+a[i].weight,tv);
else
if(tv>maxv)
{ /*調整當前最佳解*/
for(k=0;k<=i;k++)
opts[k]=cs[k];
maxv=tv;
}
cs[i]=0; /*將物品i從當前解中消去*/
}
/*考察當前選擇不包含物品i的合理性*/
if(tv-a[i].value>maxv) /*不包含物品i是可接受的*/
if(i<n-1)
tryy(i+1,tw,tv-a[i].value);
else
{ /*調整當前最佳解*/
for(k=0;k<=i;k++)
opts[k]=cs[k];
maxv=tv-a[i].value;
}
}
void main()
{
printf("Enter number of mails./n");
scanf("%d",&n);
printf("Enter limit of weight./n");
scanf("%lf",&limw);
printf("Enter weight and value of mails./n");
for(k=0;k<n;k++)
scanf("%lf%lf",&a[k].weight,&a[k].value);
for(totv=0.0,k=0;k<n;k++)
totv+=a[k].value;
maxv=0;
for(k=0;k<n;k++)
opts[k]=cs[k]=0;
tryy(0,0,totv);
for(k=0;k<n;k++)
if(opts[k])
printf("%4d",k+1);
printf("/nTotal value = %lf/n",maxv);
}

程序運行結果如下:
C程序設計例解(圖二)
    06.設有大小不等的X,Y,Z三個無刻度的油桶,分別能夠盛滿油X,Y,Z(例如,X=80,Y=50,Z=30),并約定X>Y>Z。初始時,僅X油桶盛滿油,Y和Z油桶為空。要求程序尋找一種最少的分油步聚,在某個油桶中分出T升油(例如T=40)。
解:
令三個油桶的盛油情況為倒油過程的狀態,則倒油過程就是狀態變化的過程。為了記錄倒油過程,程序引入倒油狀態隊列,將倒油過程中產生的狀態存儲在隊列中。隊列的每個元素記錄每次分油后各個油桶的分油后各個油桶的盛油量和倒油軌跡等有關信息。程序反復從隊列中取出第一個還未檢查過的狀態,對該狀態下的每個油桶判定其是否可以倒出油,及是否可以倒進油。由于油桶沒有刻度,分油時只能將某個油桶倒滿或倒空。程序分別按倒空或倒滿兩種可能的倒油動作執行不同的處理,產生新的倒油狀態,為避免某個倒油狀態在隊列中重復出現,程序只將未曾出現過的新狀態及其倒油軌跡信息存入隊列中,假定程序檢查了相當多的狀態后,或能找到解,或能確定問題無解。

倒油程序算法如下:
算法---無刻度油桶分油
{
輸入各桶容量和目標容量;
將初始狀態存入倒油狀態隊列;
設置其它初始值;
do
{
對狀態隊列中第一個還未檢查的元素
在還未檢查完每個倒出的桶且還未找到解且還未確定無解情況下循環
if(倒出桶有油)
在還未檢查完每個桶且還未找到解且還未確定無解情況下循環
if(當前桶不是倒出桶且桶還有空)
{
確定本次倒油量;
在隊列中檢查倒油后的結果狀態是否在隊列中出現;
if(結果狀態不在隊列中出現)
{
將結果狀態和軌跡信息存入隊列;
if(有桶中的油達到目標容量)
設置找到解標志;
}
}
if(還未找到解)
{
修正隊列第一個還未檢查過的元素指針;
if(隊列中的元素都已檢查過)
設置無解標志;
}
}while(還未找到解且還未確定無解);
if(找到解)
{
根據倒油步聚的軌跡信息,形成倒油步聚序列;
輸出倒油步聚序列;
}
}
倒油隊列中的元素應包含下列信息:各桶的盛油量,該狀態是從哪一個桶(源桶)倒向哪一個桶(目標桶)而形成的,形成該狀態的元素在隊列中的位置。根據以上算法編寫如下程序。

程序代碼如下:
#include<stdio.h>
#define N 100
#define BUCKETS 3
struct ele{
int state[BUCKETS]; /*各桶盛油量*/
int sbucket; /*源桶*/
int obucket; /*目標桶*/
int last; /*軌跡元素在隊列中的下標*/
}q[N]; /*隊列*/
int full[BUCKETS];
int i,j,k,found,unable,wi,wj,v,targ;
int head,tail;
void main()
{
/*輸入各桶容量和目標容量*/
printf("Enter volume of buckets./n");
for(i=0;i<BUCKETS;i++)
scanf("%d",&full[i]);
/*如要檢查full[0]>full[1]>full[2],相應代碼在此*/
printf("Enter volume of targ./n");
scanf("%d",&targ); /*檢查targ<=full[0]的代碼在此*/
/*設置將初始狀態存入倒油狀態隊列等初值*/
q[0].state[0]=full[0];
for(i=1;i<BUCKETS;i++)
q[0].state[i]=0;
q[0].sbucket=0;
q[0].obucket=0;
q[0].last=0;
found=unable=0;
head=tail=0;
do
{
/*對狀態隊列中第一個還未檢查過的元素在還未檢查完每個倒出的桶
且還未找到解且還未確定無解情況下循環*/
for(i=0;i<BUCKETS&&!found&&!unable;i++)
if(q[head].state[i]>0) /*倒出桶有油*/
/*在還未檢查完每個油桶且還未找到解且還未確定無解情況下循環*/
for(j=0;j<BUCKETS&&!found&&!unable;j++)
if(j!=i&&q[head].state[j]<full[j])
{ /*當前桶不是倒出桶且桶還有空*/
/*確定本次倒油量*/
if(q[head].state[i]>full[j]-q[head].state[j])
v=full[j]-q[head].state[j];
else v=q[head].state[i];
wi=q[head].state[i]-v;
wj=q[head].state[j]+v;
/*在隊列中檢查倒油后的結果狀態是否在隊列中出現*/
for(k=0;k<=tail;k++)
if(q[k].state[i]==wi&&q[k].state[j]==wj) break;
if(k>tail) /*結果狀態不在隊列中出現*/
{
/*將結果狀態和軌跡信息存入隊列*/
tail++;
q[tail].state[i]=wi;
q[tail].state[j]=wj;
q[tail].state[3-i-j]=q[head].state[3-i-j];
q[tail].sbucket=i+1;
q[tail].obucket=j+1;
q[tail].last=head;
/*如有桶達到目標盛油量,則設置找到解標志*/
if(wi==targwj==targ)found=1;
}
}
if(!found) /*還未找到解*/
{
head++; /*修正隊列第一個還未檢查過元素指針*/
if(head>tail) /*隊列中的元素都已檢查過*/
unable=1; /*設置無解標志*/
}
}while(!found&&!unable); /*還未找到解且還未確定無解*/
if(found) /*找到解*/
{
/*根據倒油步聚的軌跡信息,形成倒油步聚序列*/
i=tail;
j=-1;
do /*原倒油步聚逆向鏈接,現改為正向鏈接*/
{
k=q[i].last;
q[i].last=j;
j=i;
i=k;
}while(j);
/*輸出倒油步聚序列*/
for(k=q[k].last;k>=0;k=q[k].last)
{
printf("%5d to %2d:",q[k].sbucket,q[k].obucket);
for(i=0;i<BUCKETS;i++)
printf("%4d",q[k].state[i]);
printf("/n");
}
}
else printf("Unable!/n");
}
程序運行結果如下:
C程序設計例解(圖三)
QQ病毒 騰訊QQ空間代碼專題 PPT教程專題 ADSL應用面面俱到 fireworks教程專題 計算機和網絡技術基礎知識 校園網專題 網吧技術專題
07. 有2*n個盒子排成一行,其中有兩個相鄰的空盒,有n-1個盒子有符號'A',有n-1個盒子有符號'B'。例如,n=5,并有初始配置如下:
A B B A . . A B A B
試編制程序,將輸入的盒子排列狀態按以下交換規則將全部‘A'放到全部‘B'的左邊,不管相鄰兩空盒的位置。交換規則是任意兩個非空相鄰盒子的內容可移入兩個空盒中,但移動時不得變更兩符號的前后次序。編寫程序輸入初始配置后,找出達到目標要求的最少交換次數的方案。
解:
從一種盒子排列出發,將其中兩個非空相鄰盒子中的內容移入空盒的每一種移動,會使盒子產生新的排列狀態,采用試探法窮舉所有可能的移動找問題的解。首先將盒子初始排列存入移動步聚表,然后是試探和回溯循環。循環工作內容有:檢查當前排列,若當前排列是要求的最終狀態,則將達到該狀態的移動步聚保存,并回溯去找更少移動步數的解。在試探超 過限定的深度或當前狀態的所有可能移動都已試探窮盡情況下回溯;否則對當前狀態取其當前移動方法產生新的后繼狀態存入移動步聚表,并繼續向前試探。為能從某種排列出發,通過移動產生更接近目標要求的排列,對移動方法的選取作如下規定:
。擦過無意義的往返移動;
。不把兩個相鄰的同為符號‘A'的盒子向后移;
。不把兩個相鄰的同為符號‘B'的盒子向前移;
。不把兩個盒子移入到這樣的位置,移入后其首尾沒有一個與相鄰的盒子相同。
試探回溯找解算法如下:
算法---試探回溯找解
{
輸入初始排列;
初始狀態存入移動步聚表;
設置其它初值;
d=0; /*當前試探深,或當前狀態位置*/
do
{
if(當前狀態為盒子排列的終態)
{
保存解;
記錄當前解的試探深度;
回溯;
if(取盡所有可能的解)break;
}
if(試探深度超過設定值,或取盡當前狀態的所有選擇)
{
回溯;
if(取盡所有可能的選擇)break;
}
else
{
求新狀態的空盒位置;
取當前狀態的移動方法和當前狀態;
設定當前狀態的下一個移動方法;
擦過各種不希望的方法;
生成新狀態;
試探深度增1;
}
}while(1);
if(找到解)
輸出解;
}

程序代碼如下:
#include<stdio.h>
#include<string.h>
#define N 30
#define DEPTH 15
char b[2*N+1];
struct node
{
int empty; /*兩空盒的開始位置*/
char s[2*N+1]; /*盒子排列*/
int no; /*下一個移動開始的位,或稱移動方法*/
}q[DEPTH]; /*移動步聚表*/
char result[DEPTH][2*N+1]; /*存放解*/
char *s;
int best,empty,i,j,n,an,bn,sn,c,d;
void main()
{
printf("/nEnter N: ");
scanf("%d",&n);
printf("Enter initial state./n"); /*輸入初始狀態*/
for(an=bn=sn=i=0;i<2*n;)
{
c=getchar();
if(c==' ')
{
if(sn)continue; /*強制兩空白符連續出現*/
sn=1;
empty=i;
b[i++]='_';
b[i++]='_';
}
if(c=='A'c=='a')
{
if(an==n-1)continue; /*限制A的個數*/
an++;b[i++]='A';
}
if(c=='B'c=='b')
{
if(bn==n-1)continue; /*限制B的個數*/
bn++;b[i++]='B';
}
}
b[2*n]='/0';
strcpy(q[0].s,b); /*初始狀態存入移動步聚表*/
q[0].empty=empty;
q[0].no=0;
best=DEPTH-1; /*設定試探深度*/
d=0;
do
{
for(s=q[d].s; *s!='B';s++);
for(;*s&&*s!='A';s++);
if(*s=='/0') /*當前狀態為盒子排列的終態*/
{
for(j=0;j<=d;j++) /*保存解*/
strcpy(result[j],q[j].s);
best=d; /*記錄當前解的試探深度*/
d--; /*回溯*/
while(d>=0&&q[d].no==2*n-1)d--;
if(d<0)break; /*取盡所有可能的選擇*/
}
if(d>=bestq[d].no==2*n-1)
{
d--; /*回溯*/
while(d>=0&&q[d].no==2*n-1)d--;
if(d<0)break; /*取盡所有可能的選擇*/
}
else
{
empty=q[d].empty; /*新狀態的空盒位置*/
j=q[d].no++; /*取當前狀態的移動方法和設定新移動方法*/
if(d>=1&&q[d-1].empty==j)continue; /*擦過往返移動*/
s=q[d].s; /*取當前狀態*/
/*擦過各種不希望的移動*/
if(s[j]=='_'s[j+1]=='_')continue;
if(j<empty&&s[j]=='A'&&s[j+1]=='A')continue;
if(j>empty&&s[j]=='B'&&s[j+1]=='B')continue;
if(empty!=0&&s[empty-1]!=s[j]&&
(empty!=2*n-2&&s[empty+2]!=s[j+1]))continue;
if(empty==0&&s[j]=='B')continue;
if(empty==2*n-2&&s[j+1]=='A')continue;
/*生成新狀態*/
strcpy(q[d+1].s,q[d].s); /*形成移動后的狀態*/
q[d+1].s[empty]=q[d+1].s[j];
q[d+1].s[empty+1]=q[d+1].s[j+1];
q[d+1].s[j]=q[d+1].s[j+1]='_';
q[d+1].empty=j;
for(j=0;strcmp(q[j].s,q[d+1].s);j++);
if(j<=d)continue;
q[d+1].no=0;
d++; /*試探深度增1*/
}
}while(1);
if(best!=DEPTH-1)
{
printf("/n/n");
for(j=0;j<=best;j++)
printf("%s/n",result[j]);
}
}
程序運行結果如下:
C程序設計例解(圖四)


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
最近2019中文字幕大全第二页| 成人97在线观看视频| 国产一区二区激情| 91精品视频专区| 欧美精品国产精品日韩精品| 欧美日韩亚洲精品内裤| 亚洲视频免费一区| 国产区亚洲区欧美区| 亚洲男女自偷自拍图片另类| 国产一区二区三区视频在线观看| 日韩中文字幕在线观看| 国产精品久久久久高潮| 成人美女免费网站视频| 成人午夜两性视频| 日韩精品极品在线观看播放免费视频| 久久综合久久美利坚合众国| 亚洲欧洲高清在线| 国产亚洲日本欧美韩国| 亚洲国产精品999| 欧美日韩爱爱视频| 精品国产999| 国产精品揄拍一区二区| 日本精品久久中文字幕佐佐木| 亚洲欧洲黄色网| 亚洲成人激情小说| 亚洲精品乱码久久久久久金桔影视| 九九热精品视频国产| 中文字幕少妇一区二区三区| 欧美午夜激情视频| 亚洲精品永久免费精品| 91久久久久久久久久久久久| 亚洲国产精品悠悠久久琪琪| 国内精品久久久久久影视8| 亚洲欧美综合精品久久成人| 国产美女精品视频免费观看| 亚洲综合在线播放| 欧美激情在线观看视频| 精品亚洲一区二区三区| 伊人久久精品视频| 欧美亚洲成人网| 日韩精品丝袜在线| 欧美激情一区二区三区在线视频观看| 国产做受高潮69| 国产亚洲人成a一在线v站| 国产精品丝袜高跟| 国产手机视频精品| 亚洲自拍偷拍区| 国产精品夜间视频香蕉| 日韩精品免费综合视频在线播放| 欧美成人午夜免费视在线看片| 九九久久久久99精品| 欧美日韩成人免费| 成人综合网网址| 日韩在线视频观看正片免费网站| 国产一区二区色| 欧美三级欧美成人高清www| 成人a在线视频| 中文字幕日韩综合av| 国产精品入口夜色视频大尺度| 国产欧美日韩精品在线观看| 欧美激情成人在线视频| 亚洲男人天堂手机在线| 国产视频综合在线| 欧美成人精品不卡视频在线观看| 精品久久久久久久久久| 欧美国产日韩xxxxx| 欧美日韩中文字幕综合视频| 亚洲成人国产精品| 欧美韩国理论所午夜片917电影| yw.139尤物在线精品视频| 日韩av在线精品| 欧美日韩国产丝袜另类| 久久久999成人| 国产免费一区二区三区在线观看| 亚洲精品日韩久久久| 97婷婷涩涩精品一区| 91精品国产自产在线老师啪| 国产精品www色诱视频| 91在线视频九色| 亚洲欧美国产视频| 亚州成人av在线| 欧美激情国产日韩精品一区18| 97香蕉超级碰碰久久免费软件| 91成人在线播放| 亚洲一区二区免费在线| 欧美黑人性猛交| 欧美成人一区二区三区电影| 136fldh精品导航福利| 午夜精品久久久久久久白皮肤| 欧美大片免费看| 精品一区电影国产| 日韩在线免费视频观看| 日韩国产高清污视频在线观看| 久久久www成人免费精品张筱雨| 欧美猛交免费看| 欧美电影免费播放| 91精品国产99| 国产精品高潮呻吟久久av野狼| 欧洲亚洲免费在线| 中文字幕欧美日韩va免费视频| 久久99国产精品自在自在app| 欧美激情综合色综合啪啪五月| 欧美日韩中文字幕在线视频| 国产精品日韩在线观看| 国产精品免费福利| 91免费电影网站| 欧美午夜女人视频在线| 亚洲国产美女精品久久久久∴| 国产69精品久久久久久| 精品人伦一区二区三区蜜桃网站| 久久精品影视伊人网| 国产日韩欧美黄色| 国产精品99久久久久久人| 亚洲人成在线电影| 狠狠做深爱婷婷久久综合一区| 欧美在线视频网站| 91视频88av| 久青草国产97香蕉在线视频| 国产精品成人va在线观看| 成人精品视频久久久久| 亚洲天堂2020| 国产亚洲欧美视频| 91日韩在线播放| 欧美精品www| 国产一区二区三区免费视频| 黄色91在线观看| 日本成人黄色片| 日韩精品黄色网| 日韩av有码在线| 亚洲自拍小视频免费观看| 亚洲第一区中文99精品| 欧美做受高潮1| 日韩在线观看视频免费| 中文字幕亚洲一区二区三区五十路| 中文欧美日本在线资源| 69久久夜色精品国产7777| 欧美午夜精品久久久久久人妖| 久久精品亚洲热| 精品久久久在线观看| 久久久日本电影| 欧美黑人巨大精品一区二区| 一区二区三区视频在线| 欧美性生交xxxxx久久久| 精品国产电影一区| 成人黄色网免费| 亚洲第一色中文字幕| 亚洲国产精品推荐| 亚洲一区二区久久久久久| 性欧美长视频免费观看不卡| 久久视频在线直播| 国产精品va在线播放| 中文字幕日韩精品有码视频| 91亚洲永久免费精品| 精品国产一区久久久| 日韩经典第一页| 激情亚洲一区二区三区四区| 51精品在线观看| 欧美成人免费va影院高清| 伊人av综合网| 日本亚洲精品在线观看| 色噜噜狠狠狠综合曰曰曰| 欧美最顶级的aⅴ艳星| 7777kkkk成人观看| 欧美激情在线一区|