BNUZ-ACM 2018國慶新生歡樂賽部分題解+思路(已解出答案部分)
阿新 • • 發佈:2018-12-15
由於時間不足,本人在新生賽僅瀏覽了四題,其中的兩題完全通過。 下面是已解出的一題,供比對和取優。
A. 三角戀
下面貼上原題: 我的思路: 首先需要一個while(scanf)迴圈,以供測試器迴圈測試各組資料。然後因為需要輸入T組資料,所以還需要一個if迴圈或者while迴圈。資料的輸入也需要利用到到陣列,比如a[i]。再者,輸出時需要判斷是第幾次輸出,輸出一個可自增的量(%d,c++)。最後,需要一個判斷if以決定輸出嚶嚶嚶還是苦海無涯。 貼上我的程式碼,我們把它叫做程式碼a:
#include<stdio.h> int main(){ int a,b=0,c,d,i; while(scanf("%d",&a) !=EOF){ while(a--){ int g=0; b++; scanf("%d",&c); int d[c+1]; for(i=1;i<=c;i++){ scanf("%d",&d[i]); } int f=0; while(c--){ f++; if(d[d[d[f]]]==f){ printf("Case #%d: 苦海無涯\n",b); g=1; break; } } if(g==0){ printf("Case #%d: 嚶嚶嚶\n",b); } } } return 0; }
出題者提供的程式碼,我們把它叫做程式碼b:
#include<stdio.h> int main() { int T, n; int a[5005]; scanf("%d", &T); int cas = 1; while(T--) { scanf("%d", &n); int flag = 0; for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for(int i = 1; i <= n; i++) { if(a[a[a[i]]] == i){ flag = 1; break; } } if(flag){ printf("Case #%d: 苦海無涯\n",cas++); }else { printf("Case #%d: 嚶嚶嚶\n",cas++); } } return 0; }
在這裡對比一下兩段程式碼,以及寫一下他們所用到的知識。
輸入階段:
程式碼a:
while(scanf("%d",&a) !=EOF){ //輸入一個數字,決定總程式要迴圈多少次 while(a--){ //while(0)為結束 int g=0; b++; //b代表是第幾次迴圈,決定輸出case幾 scanf("%d",&c); //輸入一個數字代表人數 int d[c+1]; //定義陣列,輸入數字的值決定了要定義多少個數組 for(i = 1; i <= c; i++) scanf("%d",&d[i]); //迴圈給陣列賦值,直到結束 } }
程式碼b:
int a[5005]; //直接定義5005個數組
scanf("%d", &T);
while(T--) { //同樣迴圈T次
scanf("%d", &n);
int flag = 0;
for(int i = 1; i <= n; i++) { //迴圈賦值
scanf("%d", &a[i]);
}
這兩段程式碼的區別在於a程式碼沒有直接定義陣列的個數,b直接定義了有5005個數字,根據題目來看,其實兩種方法都可以。 while(0)代表while(false)程式將不執行,當while裡面的值仍然是非零數的時候,程式會繼續迴圈。
計算判斷階段:
程式碼a:
int f=0; //每次迴圈先將f定義為0,以方便後面判斷
while(c--){
f++; //每次迴圈自增,判斷各人是否符合條件
if(d[d[d[f]]]==f){
printf("Case #%d: 苦海無涯\n",b);
g=1; //g=1是為了跳過下方嚶嚶嚶的判斷
break; //跳出語句,不必要重複執行,減少執行時間
}
}
if(g==0) //如果不曾有過進入上方的if,則會輸出嚶嚶嚶
printf("Case #%d: 嚶嚶嚶\n",b);
程式碼b:
int cas = 1;
for(int i = 1; i <= n; i++) {
if(a[a[a[i]]] == i){
flag = 1;
break;
}
}
if(flag){ //if(flag),flag為真時,也就是等於1時進入苦海無涯
printf("Case #%d: 苦海無涯\n",cas++); //cas自增,由於兩種情況都會輸出cas,所以沒有問題
}else {
printf("Case #%d: 嚶嚶嚶\n",cas++);
}
}
在這裡講一下,為什麼是a[a[a[i]]] == i呢 我們假設有一個數組是:
1 | 2 | 3 | 4 |
---|---|---|---|
3 | 1 | 2 | 2 |
在這個數組裡面,很明顯是有三角戀的,因為1喜歡3,3喜歡2,2喜歡1。 我們把陣列看成是一種函式:
x | 1 | 2 | 3 |
---|---|---|---|
f(x) | 3 | 1 | 2 |
那麼這個表格就可以變成:
x | 1 | f(f(1)) | f(1) |
---|---|---|---|
f(x) | f(1) | f(f(f(1))) | f(f(1)) |
那麼問題就變成了f(f(f(1)))是不是等於1的問題了,同樣可以推理出可以變成f(f(f(x)))是不是等於x的問題。
程式碼部分分為兩種方式,個人認為第二種方法更好。程式碼b減少了巢狀,將函式功能模組化,便於維護與理解。同時,有良好的程式碼習慣作為基礎,這些都是我需要學習的。目前來看,我應該在程式碼的整潔性以及規範性上面下一些功夫。