acm-icpc -...

Post on 13-Mar-2020

22 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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.

top related