例76 ACM排名
問題描述
ACM國際大學生程序設計競賽是全球最具影響力的大學生程序設計競賽,它以團隊的形式代表各學校參賽,參賽隊伍最多由三名參賽隊員組成。
競賽進行5個小時,一般有7道或以上試題,由同隊的三名選手使用同一台計算機協作完成。當解決了一道試題之后,將其提交給評測機,由評測機判斷其是否正確。若提交的程序運行不正確,則該程序將被退回給參賽隊,參賽隊可以進行修改后再一次提交該問題。程序判定結果有如下7種:
1)Accepted. --通過!(AC)
2)Wrong Answer.--答案錯。(WA)
3)Runtime Error.--程序運行出錯,意外終止等。(RE)
4)Time Limit Exceeded. --超時。程序沒在規定時間內出答案。(TLE)
5)Presentation Error. --格式錯。程序沒按規定的格式輸出答案。(PE)
6)Memory Limit Exceeded. --超內存。程序沒在規定空間內出答案。(MLE)
7)Compile Error. --編譯錯。程序編譯不過。(CE)
競賽結束后,參賽各隊以解出問題(AC)的多少進行排名,若解出問題數相同,按照總用時的長短排名。總用時為每個解決了(AC)的問題所用時間之和。一個已解決問題所消耗的時間是從競賽開始到提交該問題的第一次被AC所用的時間,加上在被AC之前該問題的罰時(每次提交通不過,罰時20分鍾)。沒有解決的問題不記時。例如:A、B兩隊都正確完成兩道題目,其中A隊提交這兩題的時間分別是比賽開始后1:00和2:45,B隊為1:20和2:00,但B隊有一題提交了2次。這樣A隊的總用時為1:00+2:45=3:45,而B隊為1:20+2:00+0:20=3:40,所以B隊以總用時少而獲勝。
參與競賽的團隊根據解決問題的數量進行排名。解決相同數量問題的團隊按總時間最少排序(雖然顯示的時間以分鍾為單位,但實際時間的測量精度為1秒,在對團隊進行排名時會考慮秒數)。
根據上述規則,排名相同的團隊則按團隊編號從小到大進行排序。
編寫程序,根據某次ACM競賽中的N次提交情況,計算參加比賽的C個團隊的排名表。
輸入
輸入第1行為整數C和N(1≤ C、N≤1000),
之后N行,每行由4個整數描述一次提交情況,這4個整數為ci、pi、ti和ri,其中:ci表示團隊編號,pi表示問題編號,ti表示提交時間(以秒為單位),ri值為1或0,如果提交結果為AC,則為1,否則為0。(1 ≤ci ≤C,1≤pi≤20,1≤ ti≤36000)
輸出
輸出包含C個整數——按排名排序的團隊編號。
輸入樣例
3 3
1 2 3000 0
1 2 3100 1
2 1 4200 1
輸出樣例
2 1 3
(1)編程思路。
定義結構體類型和結構體數組
struct Teams
{
int time;
int num;
int index;
int prob[21];
}team[1001];
來保存各參賽團隊的情況。其中,成員分量index保存團隊編號,num保存團隊正確解答問題的數量,time保存團隊的總用時,數組prob保存團隊對各問題的解答情況,除團隊編號外,其余成員變量的初始值全為0。
成員數組元素prob[i]=0表示問題i未提交過,若第i題提交了,但不是正確解答,則prob[i]加1;若問題i提交被AC,則修改團隊的num和time,同時置prob[i]=-1,這表示問題i已被正確解決,以后若還有對問題i的提交,不管正確與否,均忽略不再進行處理,因為如果再更新time,只會更大,無意義。
定義結構體數組
struct Runs
{
int ci,pi,ti,ri;
} run[1001];
來保存提交情況,其中:ci表示團隊編號,pi表示問題編號,ti表示提交時間(以秒為單位),ri值為1或0,如果提交結果為AC,則為1,否則為0。
輸入了提交情況后,將run數組按提交時間從小到大進行排序,之后,遍歷數組中的每個元素進行相應處理,並對應修改提交團隊的相關成員分量。
各提交情況循環處理完后,將team數組按解答問題的正確數量num從大到小排列,若num相同,則按總用時time從小到大排列,若time還相同,則按團隊編號從小到大排列。
(2)源程序。
#include <stdio.h> #include <string.h> struct Teams { int time; int num; int index; int prob[21]; }; struct Runs { int ci,pi,ti,ri; }; int cmp1(struct Runs a,struct Runs b) { if (a.ti!=b.ti) return a.ti>b.ti; else return a.ri>b.ri; } int cmp2(struct Teams c,struct Teams d) { if (c.num!=d.num) return d.num>c.num; else if (c.time!=d.time) return c.time>d.time; else return c.index>d.index; } int main() { struct Teams team[1001]; memset(team,0,sizeof(team)); int m,n; scanf("%d%d",&m,&n); int i,j; for(i=0;i<m;i++) { team[i].index=i; team[i].time=team[i].num=0; for (j=0;j<=20;j++) team[i].prob[j]=0; } struct Runs run[1001]; for (i=0;i<n;i++) { scanf("%d%d%d%d",&run[i].ci,&run[i].pi,&run[i].ti,&run[i].ri); } for (i=0;i<n-1;i++) for (j=0;j<n-1-i;j++) { if (cmp1(run[j],run[j+1])) { struct Runs temp1; temp1=run[j]; run[j]=run[j+1]; run[j+1]=temp1; } } for (i=0;i<n;i++) { if(run[i].ri==0) { if (team[run[i].ci-1].prob[run[i].pi]!=-1) team[run[i].ci-1].prob[run[i].pi]++; } else { if (team[run[i].ci-1].prob[run[i].pi]!=-1) { team[run[i].ci-1].time+=run[i].ti+1200*team[run[i].ci-1].prob[run[i].pi]; team[run[i].ci-1].prob[run[i].pi]=-1; team[run[i].ci-1].num++; } } } for (i=0;i<m-1;i++) for (j=0;j<m-1-i;j++) { if (cmp2(team[j],team[j+1])) { struct Teams temp2; temp2=team[j]; team[j]=team[j+1]; team[j+1]=temp2; } } for (i=0;i<m-1;i++) printf("%d ",team[i].index+1); printf("%d\n",team[m-1].index+1); return 0; }
將上面的源程序提交給北大POJ題庫 POJ 2379 ACM Rank Table (http://poj.org/problem?id=2379),可以Accepted。
習題76
76-1 確定獲勝者
問題描述
某次編程競賽有4道賽題,有n只團隊參加了這一競賽。
在競賽規則中,一個團隊的得分有兩個組成部分。首先是解決了多少問題。第二個是罰分,它反映了問題解決之前的時間和錯誤提交。對於每個正確解決的問題,罰分等於解決問題的時間加上每次錯誤提交的20分鍾。對於沒有正確解決的問題,不會增加罰分。
因此,如果一個團隊在20分鍾內第二次提交時解決了問題1,他們將被罰40分。如果他們提交問題2三次,但沒有解決,他們將不被罰分。如果他們提交問題3一次,並在120分鍾內解決,他們將被處以120分的罰分。他們的總分是兩道題,共160分。
獲勝者是解決最多問題的團隊。如果團隊在解決最多問題上打成平局,那么獲勝者就是罰分最少的團隊。
請編寫程序根據給定的n個團隊的提交結果,確定最終的獲勝者。
輸入
第1行是一個整數n,表示參賽團隊數量;
之后n行,每行表示一個參賽團隊的提交情況,格式為:
<Name> <p1Sub> <p1Time> <p2Sub> <p2Time>…<p4Time>
行中的第一個元素是團隊名稱,它不包含空格。接下來,對於四個問題中的每一個,是團隊提交該問題的運行次數以及正確解決該問題的時間(兩個整數)。如果一個團隊沒有解決該問題,時間將為零。如果問題得到解決,提交的數量將至少為1。
輸入保證不會導致參賽團隊之間的平局。
輸出
輸出由一行組成,列出獲勝團隊的名稱、他們解決的問題數量以及他們的罰分。
輸入樣例
4
Stars 2 20 5 0 4 190 3 220
Rockets 5 180 1 0 2 0 3 100
Penguins 1 15 3 120 1 300 4 0
Marsupials 9 0 3 100 2 220 3 80
輸出樣例
Penguins 3 475
(1)編程思路。
定義結構體數組
struct Team
{
char name[20];
int s1,t1,s2,t2,s3,t3,s4,t4;
int total,time;
} teams[100];
來保存各參賽團隊的解答情況。其中,name保存團隊名稱,s1,t1,s2,t2,s3,t3,s4,t4分別保存團隊對4道賽題所提交的運行次數以及正確解決該問題的時間,total保存解決的問題數量,time保存團隊的總罰分。
(2)源程序。
#include <stdio.h> #include <string.h> struct Team { char name[20]; int s1,t1,s2,t2,s3,t3,s4,t4; int total,time; }; int main() { struct Team teams[100]; int i,n,win,max,cnt; scanf("%d",&n); max=-1; for(i=0;i<n;i++) { teams[i].time=0; scanf("%s%d%d%d%d%d%d%d%d",teams[i].name,&teams[i].s1 ,&teams[i].t1,&teams[i].s2,&teams[i].t2 ,&teams[i].s3,&teams[i].t3,&teams[i].s4,&teams[i].t4); cnt=0; if (teams[i].t1) { cnt++; teams[i].time+=(teams[i].s1-1)*20+teams[i].t1; } if (teams[i].t2) { cnt++; teams[i].time+=(teams[i].s2-1)*20+teams[i].t2; } if(teams[i].t3) { cnt++; teams[i].time+=(teams[i].s3-1)*20+teams[i].t3; } if(teams[i].t4) { cnt++; teams[i].time+=(teams[i].s4-1)*20+teams[i].t4; } teams[i].total=cnt; if (cnt>max) { max=cnt; win=i; } else if(cnt==max) { if(teams[i].time<teams[win].time) win=i; } } printf("%s %d %d\n",teams[win].name,teams[win].total,teams[win].time); return 0; }
76-2 排名表
問題描述
編寫一個程序,根據給定的一份參與團隊列表和一份描述參賽團隊提交的所有解決方案的日志文件,確定編程競賽的排名列表。
本次編程競賽的評分基於以下規則:
參賽團隊將根據正確解決賽題的總題數進行排名,解決相同數量問題的團隊按最少總時間排名。總時間是解決每個問題所花費的時間之和。解決問題所消耗的時間是從比賽開始到提交合格運行記錄所用的時間,再加上該問題每次被錯誤運行的20分鍾罰時(無論提交時間如何),沒有解決的問題也就沒有耗時。另外,在同一團隊提交了正確的解決方案后,之后提交錯誤的解決方案將不會受到罰時。
如果兩個或兩個以上的團隊有相同的正確答題總數和相同的總時間,則為這些團隊分配相同的排名,並按團隊名稱字母順序列出。例如,如果兩個最好的團隊解決問題的數量和總時間一致,他們都將獲得排名1,而下一個團隊將被分配到排名3。排名2在排名表中不會出現。
輸入
輸入包含多組測試用例,第1行為測試用例的組數。
對於每個測試用例,在第1行中給出團隊的數量n(1<=n<=20),在接下來的n行中給出團隊的(唯一)名稱。團隊名稱是一個長度不超過8的單詞,僅包含字母和數字,為了方便起見,團隊名稱按字母順序列出。下一行包含問題的數量k和提交的解決方案的數量m(1<=k<10,0<=m<=2000)。以下m行中的每一行都以“problem time correctness team”的形式描述了一個這樣的解決方案,其中problem是問題的編號(1 <= problem <= k),time是比賽開始后經過的分鍾數(0 <= time < 300),correctness是“Yes”或“No”,team是提交解決方案的團隊的名稱。可以假設日志文件中的行是按時間排序的。
輸出
對於每個測試用例,輸出一份包含參加比賽的每個團隊的排名列表。格式是“rank.team solved time”,其中rank是排名,team是團隊名稱,solved是正確解題的數量,time是總時間。除了分隔這四個字段的單個空格外,還可以使用字段寬度2表示排名,8表示團隊名稱,1表示已解決問題的數量,4表示總時間(名稱左對齊,數字右對齊,請參見輸出樣例),使表格看起來更漂亮。每個測試用例都以一個空行結束。
輸入樣例
2
10
Team1
Team2
Team3
Team4
Team5
Team6
Team7
Team8
Team9
slowTeam
8 14
1 18 Yes Team4
1 57 Yes Team2
1 87 Yes Team3
1 101 Yes Team1
2 103 Yes Team5
2 120 Yes Team6
6 141 Yes Team7
1 147 No Team1
7 156 Yes Team2
5 167 Yes Team8
2 167 Yes Team9
5 170 No Team4
5 175 Yes Team4
1 234 No slowTeam
1
Team1
8 0
輸出樣例
1. Team2 2 213
1. Team4 2 213
3. Team3 1 87
4. Team1 1 101
5. Team5 1 103
6. Team6 1 120
7. Team7 1 141
8. Team8 1 167
8. Team9 1 167
10. slowTeam 0 0
1. Team1 0 0
(1)編程思路。
參照例76的編程思路進行處理,但由於輸入的提交情況已按提交時間排序,因此無需對輸入的提交情況進行排序,這樣也就不需要用結構體數組來保存各提交情況,每輸入一個提交情況,就直接進行處理。
(2)源程序。
#include <stdio.h> #include <string.h> struct Teams { char name[10]; int index; int time; int num; int prob[11]; }; int cmp(struct Teams a,struct Teams b) { if (a.num!=b.num) return b.num>a.num; else if (a.time!=b.time) return a.time>b.time; else return a.index>b.index; } int main() { struct Teams team[21]; memset(team,0,sizeof(team)); int t; scanf("%d",&t); while (t--) { int n; scanf("%d",&n); int i,j; for (i=0;i<n;i++) { scanf("%s",team[i].name); team[i].time=0; team[i].num=0; team[i].index=i+1; for (j=0;j<10;j++) team[i].prob[j]=0; } int k,m; scanf("%d%d",&k,&m); for (i=0;i<m;i++) { int pno,ts; char corr[5],name[10]; scanf("%d%d%s%s",&pno,&ts,corr,name); int id; for (id=0;id<n;id++) if (strcmp(team[id].name,name)==0) break; if (corr[0]=='N') { if (team[id].prob[pno]!=-1) team[id].prob[pno]++; } else { if (team[id].prob[pno]!=-1) { team[id].time+=(ts+20*team[id].prob[pno]); team[id].prob[pno]=-1; team[id].num++; } } } for (i=0;i<n-1;i++) for (j=0;j<n-1-i;j++) { if (cmp(team[j],team[j+1])) { struct Teams temp; temp=team[j]; team[j]=team[j+1]; team[j+1]=temp; } } int rank=0; for (i=0;i<n;i++) { if (i==0 || team[i].num!=team[i-1].num || team[i].time!=team[i-1].time) rank=i+1; printf("%2d. %-8s %d %4d\n",rank,team[i].name,team[i].num,team[i].time); } printf("\n"); } return 0; }
將上面的源程序提交給北大POJ題庫POJ 1918 Ranking List (http://poj.org/problem?id=1918) ,可以Accepted。
76-3 競賽排名
問題描述
某次程序設計競賽有7道題目,有C只團隊參加競賽。
團隊排名順序為:首先是解決的問題最多,其次是總時間最少,然后是所有非零時間的最小幾何平均數。仍處於平局的團隊將獲得相同的數字排名,並按團隊名稱區分大小寫的字符串比較按字母順序列出。
對於這個問題,所有幾何平均值都將被四舍五入為一個整數,如下所述,在計算排名和顯示結果時,只使用四舍五入值。
如果所有時間均為零,則幾何平均值也為零。否則,如果有n個非零乘以t1,…,tn,則幾何平均值定義為 exp((ln t1+ ln t2+…+ln tn)/n)
其中exp x表示ex,ln x表示x的自然對數。計算幾何平均值后,通過加0.5並截斷任何小數位數將其四舍五入為整數。
編寫程序,對這個編程競賽進行排名。
輸入
輸入文件包含一個或多個競賽,后面有一行僅包含零,表示文件結束。
每場比賽以一行開頭,其中包含一個不大於20的正整數c,表示比賽中的團隊數量,然后是c行,其中包含團隊名稱和七個問題的解決時間,用空格分隔。團隊名稱由1到10個字母組成。比賽中的所有團隊名稱都是唯一的。時間是不大於500的非負整數。
輸出
對於每場比賽,必須用表格形式輸出排名。所有表格的寬度相同,長度等於參賽隊伍的數量。使用示例中所示的精確格式。每場比賽都有一個編號的標題,后面是一個表格,每行有一個團隊條目。每個條目都包含排名、團隊名稱、解決的問題、總時間、幾何平均數,然后是與輸入中出現的順序相同的單個解決時間。團隊名稱左對齊,所有其他字段右對齊。排名總是有兩位數,必要時包括前導零。空格永遠不會出現在行首或行尾。
輸入樣例
1
Plutonians 123 234 345 456 167 278 389
4
Xap 0 0 0 0 0 0 0
Foo 20 30 0 50 40 0 10
Bar 0 50 20 0 10 40 30
Baz 0 0 0 0 0 0 0
3
Venus 213 0 0 57 0 0 0
Neptune 0 0 0 117 153 0 0
Mars 0 150 0 0 0 0 120
0
輸出樣例
(1)編程思路。
定義結構體數組
struct Team
{
char name[12];
int sol, tot, g, p[7], ind;
} teams[25];
來保存各團隊的參賽情況。其中,name保存團隊名稱,ind保存團隊的最后名次,sol保存團隊解決問題的數量,tot保存團隊解決問題的總時間,g保存幾何平均數,數組p[7]保存7個問題的單個解決時間。
(2)源程序。
// POJ 1245 Programmer, Rank Thyself (http://poj.org/problem?id=1245)
#include <stdio.h> #include <string.h> #include <math.h> struct Team { char name[12]; int sol, tot, g, p[7], ind; }; struct Team teams[25]; int cmp(struct Team a, struct Team b) { if (a.sol!=b.sol) return b.sol>a.sol; else if (a.tot!=b.tot) return a.tot > b.tot; else if (a.g!=b.g) return a.g > b.g; else return strcmp(a.name, b.name)>=0; } int main() { int n=0,cnt=1,i,j; while(scanf("%d", &n) && n!=0) { for (i=0; i<n;i++) { double t = 0; teams[i].sol = 0, teams[i].tot = 0, teams[i].g = 0; scanf("%s", teams[i].name); for(j=0; j<7; j++) { scanf("%d", &teams[i].p[j]); if(teams[i].p[j]) { teams[i].sol++; teams[i].tot += teams[i].p[j]; t += log((double)teams[i].p[j]); } } if(teams[i].sol > 0) teams[i].g = exp(t/teams[i].sol) + 0.5; } for (i=0;i<n-1;i++) for (j=0;j<n-1-i;j++) { if (cmp(teams[j],teams[j+1])) { struct Team temp; temp=teams[j]; teams[j]=teams[j+1]; teams[j+1]=temp; } } printf("CONTEST %d\n", cnt); cnt++; for(i=0; i<n; i++) { if(i < 9) printf("0"); if(i > 0 && teams[i].sol == teams[i-1].sol && teams[i].tot == teams[i-1].tot && teams[i].g == teams[i-1].g) teams[i].ind = teams[i-1].ind; else teams[i].ind = i + 1; printf("%d %-10s %d %4d %3d %3d %3d %3d %3d %3d %3d %3d\n", teams[i].ind, teams[i].name, teams[i].sol, teams[i].tot, teams[i].g, teams[i].p[0], teams[i].p[1], teams[i].p[2], teams[i].p[3], teams[i].p[4], teams[i].p[5], teams[i].p[6]); } } return 0; }