ACM-ICPC -...
Transcript of ACM-ICPC -...
2012/6/14
1
ACM-ICPC
June 22, 2012 Prog 0 Special lecture
m5161121 Yohei Mori, University of AIZU
ACM-ICPCロゴ
ACM-ICPC
• ACMが主催するプログラミングコンテスト。
– ACM(Association for Computing Machinery)
• ICPC
– INTERNATIONAL (国際)
– COLLEGIATE (大学対抗)
– PROGRAMMING
– CONTEST(プログラミングコンテスト)
Rule
• 大学内で3人1組のチーム。
• 時間内により多くの”問題”をプログラムを用いて解けば勝ち。
• チームで1台のコンピュータ。
–並列コーディング不可。
– コードを書く人、解法を考える人、など得意によって分担が存在するチームもある。
• その他細かい規定。
問題を解くと対応した色の風船があがる。
Roadmap
1. チーム編成
2. チーム登録
3. 国内予選
4. 突破したら、アジア地区大会(日本か遠征でアジア諸外国)
5. 地区大会も突破したら、世界大会
– 2008年度大会で会津大は世界大会(Stockholm)に出場している。
What is Problem Solving
• 問題を解く流れ。
1. 問題が何を求めているか理解する。
どんな問題か、得意そうな人がいたらそのメンバーに相談、あるいは任せる。
2. 問題の制約(変数の条件)を理解する。
3. 適切な解法を考える。
4. プログラムで実装する。
5. ジャッジシステムにかける。
たとえばOnline Judge(後出)。
2012/6/14
2
Problem
• ACM-ICPC 2011 国内予選 問題A
• 何個かの正の整数nに対して、nより大きく2n以下の素数の数を求めよ。
–素数とは? • 1と自身以外の数すべてで割りきれない整数。
• n<=123,456
• nが何個かはわからない。
Solution
• 123456以下の素数をすべて求めればいい。
• ある数xが素数であるかどうか(素数判定)。
– 2以上x未満の数でxを割りきる場合xは素数ではない。
int is_x_prime = 1;
for(int i = 2; i < x; ++i){
if( x % i == 0 ) is_x_prime = 0;
}
if( is_x_prime ) printf(“%d is prime!¥n”, x);
Solution (cont.)
• 正の整数nを次々に読み取り、nより大きく2n
以下の数すべてについて素数判定し、素数だった数をカウントする。
• nが0のときプログラムを終了する。
Code
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
while(1){
int i, x, n;
int res = 0;
scanf("%d", &n);
if( n == 0 ) break;
for(x = n+1; x <= 2*n; ++x){
int is_x_prime = 1;
for(i = 2; i < x; ++i){
if( x % i == 0 ){
is_x_prime = 0;
}
}
if( is_x_prime ) ++res;
}
printf("%d¥n", res);
}
return (EXIT_SUCCESS);
}
Execution Example
• n=5のときnより大きくから2n以下の数:6,7,8,9,10の中にたしかに素数7がひとつだけある。
• 実際の解答プログラムには”n = “や”Answer : “といった文字列は要らない。
Verification
• ジャッジシステムにかける。
• しかし、本番のジャッジシステムはいつでも使用できるわけではないので、Online Judgeと呼ばれるWebサービスに「投げ(Submit) 」る。
• Online Judgeは主にコンテストの過去問題を
保存し、対応する問題に対して解答プログラムを判定することができる。
2012/6/14
3
Online Judge
• 会津大学のデータベース研究室で運用されているAizu Online Judge(AOJ)を使用。
Problem Selection
• 今の問題を探す(AOJに収録済み)。
–ちなみに国内予選7問のうち、最初の問題なので簡単な問題。
問題1172: Chebyshev’s Theorem 正答率:72.63%, 正解者:205人
Submission
• Submitボタンで投げる。
• C言語のほか、C++,C++11,C#,D,Javaも対応。
Submission
• Waiting Judge (判定待ち)
Judge Result
• Time Limit Exceeded(時間超過)
–あなたのプログラムは実行時間が長すぎます。
Time Limit ?
• 長すぎるとは?
–時間制限があり、8秒。
• 8秒以内に入力ファイルに書かれている整数nすべてに対して正しい出力をする必要。
– しかしnが一体いくつあるかは書いていない。
– n=123456(制約の上限)を入力すると…
• 1172.in に n がひとつ書かれている。
• 約6秒かかる(@2.80GHz, 1 thread)。
2012/6/14
4
What is WORST Case?
• もしnが何百個もあり、すべて100,000程度の数だったら…?
–オンラインジャッジでは独自、あるいは大会公式の入力を用意している。
–入力は厳しい。
• ひとつひとつのnに対して高速に答えを求めなければならない。
↓たとえば
Another Solution
• 素数pの倍数Pは素数ではない –なぜならPは明らかにpで割り切れる。
• 配列isPrimeにその添え字が素数かどうかを記録する。 – isPrime[2] = 1, isPrime[3] = 1, isPrime[4] = 0,
isPrime[5] = 1 … • あるisPrime[i] = 1となるiについて、isPrime[i*j] = 0である(j>=2, i*j<=123456)。
– isPrime[x] を見れば xが素数かどうか一瞬でわかる。
Code #include<stdio.h>
#include<stdlib.h>
#define N 2*123456
int main(int argc, char *argv[])
{
int i, j;
int isPrime[1+N];
// すべての整数が素数と仮定
for(i = 2; i <= N; ++i){
isPrime[i] = 1;
}
// 素数である整数の倍数を素数でないとする
for(i = 2; i < N; ++i){
if( isPrime[i] ){
for(j = 2; i * j < N; ++j){
isPrime[i * j] = 0;
}
}
}
while(1){
int x, n;
int res = 0;
scanf("%d", &n);
if( n == 0 ) break;
for(x = n+1; x <= 2*n; ++x){
if( isPrime[ x ] ) ++res;
}
printf("%d¥n", res);
}
return (EXIT_SUCCESS);
}
Submission
• Waiting Judge (判定待ち)
Judge Result
• Wrong Answer (誤答)
–あなたのプログラムには誤りがあります。
2012/6/14
5
What is WRONG ?!
• 何が違うか?
– もう一度コードを見直す。
Wrong Code #include<stdio.h>
#include<stdlib.h>
#define N 2*123456
int main(int argc, char *argv[])
{
int i, j;
int isPrime[1+N];
for(i = 2; i <= N; ++i){
isPrime[i] = 1;
}
for(i = 2; i < N; ++i){
if( isPrime[i] ){
for(j = 2; i * j < N; ++j){
isPrime[i * j] = 0;
}
}
}
while(1){
int x, n;
int res = 0;
scanf("%d", &n);
if( n == 0 ) break;
for(x = n+1; x <= 2*n; ++x){
if( isPrime[ x ] ) ++res;
}
printf("%d¥n", res);
}
return (EXIT_SUCCESS);
}
Debug
• isPrime[N=2*123456=246912] は 0でなければならない。
– 2*123456は明らかに素数ではないから。
– しかし (i * j < N=246912)では初期化以降0になることがない。
Corrected Code #include<stdio.h>
#include<stdlib.h>
#define N 2*123456
int main(int argc, char *argv[])
{
int i, j;
int isPrime[1+N];
for(i = 2; i <= N; ++i){
isPrime[i] = 1;
}
for(i = 2; i < N; ++i){
if( isPrime[i] ){
for(j = 2; i * j <= N; ++j){
isPrime[i * j] = 0;
}
}
}
while(1){
int x, n;
int res = 0;
scanf("%d", &n);
if( n == 0 ) break;
for(x = n+1; x <= 2*n; ++x){
if( isPrime[ x ] ) ++res;
}
printf("%d¥n", res);
}
return (EXIT_SUCCESS);
}
Submission
• Waiting Judge (判定待ち)
Judge Result
• Accepted(正答)
–あなたのプログラムが”このOnline Judge上で”正しいことを保証します。
ちなみにs1160219は学部時代のIDです。
2012/6/14
6
Merits
• 数学的/論理的思考力・問題解決能力の向上
• 効率のよいコードを速く、正確に書く力
• チーム内での意思疎通
–あるいは競技プログラミングを趣味とする人々とのつながり。
• 就職につながるかも(スポンサー企業)
Sponsors
End
• ACM-ICPCに関して興味がわいた人
– ICPCに向けた練習を行うサークルがあります。部長(s1180008@u-aizu, Kazuki Omomo)か顧問の先生(yutaka@u-aizu, Yutaka Watanobe)にメールしてみましょう。
• Good luck & Have a fun for your ADVANCED programming.