一開始用單向循環鏈表來實現,提交的時候編譯錯誤,看到好多人都是類似的錯誤,可能是網站出了問題,其實即使沒問題也通不過的,當算到k=10的時候就已經很卡了。換了一種方法,用數組來實現,這下網站好了,確實還是TLE,到10的時候雖然比用鏈表要快一些,但還是卡。最後實在沒轍,看到網上有人用數學的方法,推出計算m的公式。沒仔細去看推的過程。最後只能用自己用數組實現的方法來計算出1-13對應的m值,然後打表了~~不過,這道題還是讓我運用了一下鏈表,以前都沒怎麼實際運用過。
方法一:用鏈表來實現(會超時)
#include<stdio.h>
#include<malloc.h>
#include<memory.h>
struct Node
{
int num;
Node *next;
};
typedef Node *ptrToNode;
typedef ptrToNode List;//指向結點的鏈表
typedef ptrToNode position;
int *excuted;
position Find(int x, List list);//查找鏈表中的元素x,返回其位置
int result[14]={0};//將已經計算過得k對應的m值保存起來,便於下次直接使用
int main()
{
List list;
position p,ptemp;
int i, j, k, kk, m, count;
while(1)
{
count = 0;
scanf("%d", &k);
if(k == 0)
return 0;
if(result[k-1]!=0)
{
printf("%d\n", result[k-1]);
continue;
}
kk = 2*k;
list = (Node *)malloc(sizeof(Node));
excuted = (int *)malloc(sizeof(int)*kk);
if(list==NULL || excuted==NULL)
{
printf("malloc failed!\n");
return 1;
}
memset(excuted, 0, sizeof(int)*kk);
list->num = 1;//每個結點保存每個人的編號,無頭結點
list->next = NULL;
for(i=2; i<=kk; i++)
{
p = (Node *)malloc(sizeof(Node));//爲每個結點分配空間
if(p==NULL)
{
printf("malloc failed!\n");
return 1;
}
p->num = i;
//printf("%d\n", p->num);
if(list->next==NULL)
{
list->next = p;
}
else
{
ptemp->next = p;
}
ptemp = p;
p->next = NULL;
}
p->next = list;//循環鏈表
p = list;
/*for(i=0; i<kk; i++)
{
printf("%d\n", p->num);
p = p->next;
}*/
m = k+1;
p = list;
while(count!=k)
{
for(i=1; i<m;)
{
if(excuted[p->num-1]==1)//跳過已經處死的結點
{
p = p->next;
}
else if(excuted[p->num-1]==0)
{
p = p->next;
while(excuted[p->num-1]==1)
p = p->next;
i++;
}
}
//printf("%d\n", p->num);
if(p->num<=k)//該m不合適,恢復excuted,增加m,重新開始
{
memset(excuted, 0, sizeof(int)*kk);
if(m%kk==0)
m += k+1;
else
{
m++;
while(m%(k+1)!=0 && m%(k+1)!=1)
m++;
}
count = 0;
p = list;
}
else
{
excuted[p->num-1] = 1;
while(1)
{
if(excuted[p->next->num-1]==0)
break;
p = p->next;
}
p = p->next;
count++;
}
}
printf("%d\n", m);
result[k-1] = m;
//釋放鏈表
p = list->next;
for(i=0; i<kk-1; i++)
{
ptemp = p->next;
free(p);
p = ptemp;
}
free(list);
free(excuted);
}
return 0;
}
#include<stdio.h>
#include<memory.h>
int num[26]={0};//保存每個人的編號
int excuted[26];//標記被處死的人,爲1表示已經被處死
int result[13]={0};//將已經計算過得k對應的m值保存起來,便於下次直接使用
int main()
{
int i, j, k, kk, m, count,tm;
while(1)
{
count = 0;
scanf("%d", &k);
if(k == 0)
return 0;
if(result[k-1]!=0)
{
printf("%d\n", result[k-1]);
continue;
}
kk = 2*k;
for(i=0; i<kk; i++)
{
num[i] = i+1;
}
m = k+1;
j = 0;
while(count!=k)
{
for(i=1; i<m;)
{
if(excuted[num[j]-1]==1)//跳過已經處死的結點
{
j++;
if(j>=kk)//到達數組的末尾
j=0;
}
else if(excuted[num[j]-1]==0)
{
while(1)
{
j++;
if(j>=kk)//到達了數組的末尾
j=0;
if(excuted[num[j]-1]==0)
break;
}
i++;
}
}
//printf("%d\n", num[j]);
if(num[j]<=k)//該m不合適,恢復excuted,增加m,重新開始
{
memset(excuted, 0, sizeof(int)*kk);
if(m%kk==0)
m += k+1;
else
{
m++;
while(m%(k+1)!=0 && m%(k+1)!=1)//m必須爲k+1的整數倍或k+1的整數倍加1,因爲當只剩下k+1個人時j必位於k或k+1的位置上
{
if(m%kk==0)
m += k+1;
else
m++;
}
}
count = 0;
j = 0;
}
else
{
excuted[num[j]-1] = 1;
while(1)
{
j++;
if(j>=kk)//到達了數組的末尾
j=0;
if(excuted[num[j]-1]==0)
break;
}
count++;
}
}
printf("%d\n", m);
result[k-1] = m;
}
return 0;
}
//用上述方法能得到正確結果,但是當k到10的時候就會卡,要超時
//實在沒找到好的方法,只能先將結果算出再通過打表來輸出結果
//可以參考http://topic.csdn.net/u/20111118/13/7c4c52b4-d00b-4d4e-b52d-b9c8fdd4b24b.html
//用數學方法來推出計算m的公式
#include<stdio.h>
int result[13]={2,7,5,30,169,441,1872,7632,1740,93313,459901,1358657,2504881};//將已經計算過得k對應的m值保存起來,便於下次直接使用
int main()
{
int k;
while(1)
{
scanf("%d", &k);
if(k == 0)
break;
else
{
printf("%d\n", result[k-1]);
}
}
return 0;
}