ープのロープ長以下であれば実現可能である ケース 3: 3 本のロープの杭の位置を点 P 1 = (x 1, y 1, 0), 点 P 2 = (x 2, y 2, 0), 点 P 3 = (x 3, y 3, 0) とする 点 P 1 = (x 1, y 1, 0), 点 P 2 = (x 2,

Similar documents
文字数は1~6なので 同じ本数の枝を持つパスで生成される呪文の長さは最大で6 倍の差がある 例えば 上図のようなケースを考える 1サイクル終了した時点では スター節点のところに最強呪文として aaaaaac が求まる しかしながら サイクルを繰り返していくと やがてスター節点のところに aaaaaa

プログラム例 /* ACM-ICPC2009 国内予選 Problem C */ // // filename = pc1.c // コンパイル

Microsoft Word - ICPC2014_DomG.docx

[Problem F] 古い記憶 良さそうな方法は思いつかなかった アイディア募集中!!! かなり強引に解いている 各判定データに対して 30 秒程度かかる 元の文章と改ざん文章の関係を考える ウィルス感染の可能性は高々 2 回であり 各々の感染では 1 文字削除 1 文字追加 1 文字変更が行われ

プログラミング基礎

Taro-数値計算の基礎Ⅱ(公開版)

プログラミング基礎

プログラミング方法論 II 第 14,15 回 ( 担当 : 鈴木伸夫 ) 問題 17. x 座標と y 座標をメンバに持つ構造体 Point を作成せよ 但し座標 は double 型とする typedef struct{ (a) x; (b) y; } Point; 問題 18. 問題 17 の

プログラミング基礎

[Problem D] ぐらぐら 一般に n 個の物体があり i 番目の物体の重心の x 座標を x i, 重さを w i とすると 全体の n 重心の x 座標と重さ w は x = ( x w ) / w, w = w となる i= 1 i i n i= 1 i 良さそうな方法は思いつかなかった

kiso2-09.key

Taro-再帰関数Ⅱ(公開版).jtd

[1] #include<stdio.h> main() { printf("hello, world."); return 0; } (G1) int long int float ± ±

C による数値計算法入門 ( 第 2 版 ) 新装版 サンプルページ この本の定価 判型などは, 以下の URL からご覧いただけます. このサンプルページの内容は, 新装版 1 刷発行時のものです.

Microsoft PowerPoint - 05.pptx

#define N1 N+1 double x[n1] =.5, 1., 2.; double hokan[n1] = 1.65, 2.72, 7.39 ; double xx[]=.2,.4,.6,.8,1.2,1.4,1.6,1.8; double lagrng(double xx); main

Taro-最大値探索法の開発(公開版

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

Microsoft Word - 3new.doc

x(t) + t f(t, x) = x(t) + x (t) t x t Tayler x(t + t) = x(t) + x (t) t + 1 2! x (t) t ! x (t) t 3 + (15) Eular x t Teyler 1 Eular 2 Runge-Kutta

Q.5-1 Ans.

スライド 1

/* do-while */ #include <stdio.h> #include <math.h> int main(void) double val1, val2, arith_mean, geo_mean; printf( \n ); do printf( ); scanf( %lf, &v

Taro-リストⅠ(公開版).jtd

memo

< F2D837C E95CF CF68A4A94C5816A2E6A>


main

‚æ4›ñ

Taro-再帰関数Ⅲ(公開版).jtd

Taro-リストⅢ(公開版).jtd

2014年度 名古屋大・理系数学

#6 : ( 8-13) URL : j inoue/index.html : Neugart

Microsoft Word - no206.docx

Taro-スタック(公開版).jtd

memo

02: 変数と標準入出力

第9回 配列(array)型の変数

31 33

02: 変数と標準入出力

PowerPoint Presentation

p = 1, 2, cos 2n + p)πj = cos 2nπj 2n + p)πj, sin = sin 2nπj 7.1) f j = a ) 0 + a p + a n+p cos 2nπj p=1 p=0 1 + ) b n+p p=0 sin 2nπj 1 2 a 0 +


PowerPoint プレゼンテーション

講習No.10

PowerPoint Presentation

Microsoft PowerPoint - kougi9.ppt

1. 入力した正の整数を降順に並べ換えて出力するプログラムを作成せよ プログラムは個別にコンパイルし make コマンドで実行すること 入力データは 50 以下とし 以下の数が混在しているとする 16 進数 : 先頭 1 文字が x または X( エックスの小文字か大文字 ) 8 進数 : 先頭 1

<4D F736F F D20438CBE8CEA8D758DC F0939A82C282AB2E646F63>

£Ã¥×¥í¥°¥é¥ß¥ó¥°ÆþÌç (2018) - Â裵²ó ¨¡ À©¸æ¹½Â¤¡§¾ò·ïʬ´ô ¨¡

2014年度 センター試験・数学ⅡB

kiso2-06.key

untitled

x h = (b a)/n [x i, x i+1 ] = [a+i h, a+ (i + 1) h] A(x i ) A(x i ) = h 2 {f(x i) + f(x i+1 ) = h {f(a + i h) + f(a + (i + 1) h), (2) 2 a b n A(x i )

Microsoft Word - no103.docx

Microsoft PowerPoint - 計算機言語 第7回.ppt

Math-Aquarium 例題 図形と計量 図形と計量 1 直角三角形と三角比 P 木の先端を P, 根元を Q とする A 地点の目の位置 A' から 木の先端への仰角が 30,A から 7m 離れた AQB=90 と なる B 地点の目の位置 B' から木の先端への仰角が 45 であ るとき,

Taro-ポインタ変数Ⅰ(公開版).j

Microsoft Word - Training10_プリプロセッサ.docx

スライド 1

( ) 1 1: 1 #include <s t d i o. h> 2 #include <GL/ g l u t. h> 3 #include <math. h> 4 #include <s t d l i b. h> 5 #include <time. h>

1 return main() { main main C 1 戻り値の型 関数名 引数 関数ブロックをあらわす中括弧 main() 関数の定義 int main(void){ printf("hello World!!\n"); return 0; 戻り値 1: main() 2.2 C main

Microsoft Word - COMP-MATH-2016-FULLTEXT.doc

program7app.ppt

Microsoft PowerPoint - lec4.ppt

講習No.9

joho12.ppt

char int float double の変数型はそれぞれ 文字あるいは小さな整数 整数 実数 より精度の高い ( 数値のより大きい より小さい ) 実数 を扱う時に用いる 備考 : 基本型の説明に示した 浮動小数点 とは数値を指数表現で表す方法である 例えば は指数表現で 3 書く

6 6.1 sound_wav_files flu00.wav.wav 44.1 khz 1/44100 spwave Text with Time spwave t T = N t N 44.1 khz t = 1 sec j t f j {f 0, f 1, f 2,, f N 1

P06.ppt

18 C ( ) hello world.c 1 #include <stdio.h> 2 3 main() 4 { 5 printf("hello World\n"); 6 } [ ] [ ] #include <stdio.h> % cc hello_world.c %./a.o

Microsoft Word - no202.docx

PowerPoint プレゼンテーション

Microsoft PowerPoint - 06.pptx

Microsoft Word - スーパーナビ 第6回 数学.docx

Microsoft PowerPoint - C言語の復習(配布用).ppt [互換モード]

2. 整数の値を 3 つ 引数として受け取ってそのうち最大の値を返す関数 int max(int a,int b,int c) 3 つの中からの最大値, と値が少ないので, 配列を使わずにごり押しで最大値を求めてみ ました. 配列を使う方法については今までの解答を見ればわかるはずです. その場合受け

Taro-プログラミングの基礎Ⅱ(公

スライド 1

C 2 / 21 1 y = x 1.1 lagrange.c 1 / Laglange / 2 #include <stdio.h> 3 #include <math.h> 4 int main() 5 { 6 float x[10], y[10]; 7 float xx, pn, p; 8 in

r07.dvi

ohp07.dvi

演習課題No12

C のコード例 (Z80 と同機能 ) int main(void) { int i,sum=0; for (i=1; i<=10; i++) sum=sum + i; printf ("sum=%d n",sum); 2

Microsoft Word - Cプログラミング演習(12)

Microsoft PowerPoint - 3.pptx

PowerPoint プレゼンテーション

PowerPoint Presentation

スライド 1

フローチャートの書き方

comment.dvi

Microsoft PowerPoint - 4.pptx

C 言語第 3 回 2 a と b? 関係演算子 a と b の関係 関係演算子 等しい a==b 等しくない a!=b より大きい a>b 以上 a>=b より小さい a<b 以下 a<=b 状態 真偽 値 条件が満たされた場合 TRUE( 真 ) 1(0 以外 ) 条件が満たされなかった場合 F

/*Source.cpp*/ #include<stdio.h> //printf はここでインクルードして初めて使えるようになる // ここで関数 average を定義 3 つの整数の平均値を返す double 型の関数です double average(int a,int b,int c){

関数の呼び出し ( 選択ソート ) 選択ソートのプログラム (findminvalue, findandreplace ができているとする ) #include <stdiu.h> #define InFile "data.txt" #define OutFile "surted.txt" #def

DA13

£Ã¥×¥í¥°¥é¥ß¥ó¥°ÆþÌç (2018) - Â裶²ó ¨¡ À©¸æ¹½Â¤¡§·«¤êÊÖ¤· ¨¡

Microsoft Word - no205.docx

Gauss

Java 基礎問題ドリル ~ メソッドを理解する ~ 次のプログラムコードに 各設問の条件にあうメソッドを追加しなさい その後 そのメソッドが正しく動作することを検証するためのプログラムコードを main メソッドの中に追加しなさい public class Practice { // ここに各設問

Transcription:

ACM ICPC2013 国内予選問題 E つながれた風船 風船が最も高くあがるケースとして 1. 一本のロープが垂直に延びて他の2 本は緩んでいる 2. 二本のロープがピンと張っており残りの1 本は緩んでいる 3. 三本のロープともピンとはっているの三つのケースが考えられる ロープの本数は高々 10 本なので ケース1 は高々 10 9C2=360 通り ケース2も高々 10C2 8=360 通り ケース3は高々 10C3=120 通りしかないので これら全ての場合についてその実現可能性と実現可能な場合の風船と高さを求めることで 最も高く上がるケースの高さを求めることができる ケース 1: i 番目のロープがピンと張った状態だとすると 風船の座標は (x i, y i, r i ) となる 1 この位置から他の 2 本のロープの杭の位置までの距離がそのロープのロープ長以下であれば実現可能である ケース 2: ピンと張っているロープの杭の位置を点 P 1 = (x 1, y 1, 0), 点 P 2 = (x 2, y 2, 0) とする 点 P 1 = (x 1, y 1, 0), 点 P 2 = (x 2, y 2, 0) を中心とする半径 r 1, r 2 の球の交点で z 座標が最大のものを P = (x, y, z) とする この時 P 0 =(x, y, 0) とすると P 0 は直線 P 1 P 2 上の点であり 線分 PP 0 は点 P から x-y 平面への垂線となる P 1 P 2 = d, P 1 P = d 1, PP 2 = d 2 とすると d 2 = (x 2 x 1 ) 2 + (y 2 y 1 ) 2 ( 式 1.1) r 12 = d 12 + z 2 ( 式 1.2) r 2 2 = d 2 2 + z 2 ( 式 1.3) d = d 1 + d 2 ( 式 1.4) ( 式 1.4) を ( 式 1.3) に代入し ( 式 1.2) を引いて整理すると d 1 = (d 2 + r 2 1 r 2 2 )/2d ( 式 2.1) これらを用いて z 2 = r 2 1 d 2 1 = [4 r 2 1 r 2 2 d 2 (r 2 1 + r 2 2 ) 2 ] / 4d 2 ( 式 3.1) x = x 1 + (x 2 x 1 ) d 1 / d ( 式 3.2) y = y 1 + (y 2 y 1 ) d 1 / d ( 式 3.3) この時 z2 が非負で 点 P から残りのロープの杭の位置までの距離がそのロ 1 ここでは i 番目のロープの長さを r i としている

ープのロープ長以下であれば実現可能である ケース 3: 3 本のロープの杭の位置を点 P 1 = (x 1, y 1, 0), 点 P 2 = (x 2, y 2, 0), 点 P 3 = (x 3, y 3, 0) とする 点 P 1 = (x 1, y 1, 0), 点 P 2 = (x 2, y 2, 0), 点 P 3 = (x 3, y 3, 0) を中心とする半径 r 1, r 2, r 3 の球の交点を P = (x, y, z) とすると (x 1 x) 2 + (y 1 y) 2 + z 2 2 = r 1 ( 式 1.1) (x 2 x) 2 + (y 2 y) 2 + z 2 2 = r 2 ( 式 1.2) (x 3 x) 2 + (y 3 y) 2 + z 2 2 = r 3 ( 式 1.3) ( 式 1.2) と ( 式 1.3) から ( 式 1.1) を引いて整理すると (x 2 x 1 ) x + (y 2 y 1 ) y = (A 2 A 1 )/2 ( 式 2.1) (x 3 x 1 ) x + (y 3 y 1 ) y = (A 3 A 1 )/2 ( 式 2.1) ここで A i = r 2 i x 2 2 i y i [ i = 1, 2, 3] である また x ij = x i x j, y ij = y i y j, A i1 = (A i A 1 )/2 とおくと ( 式 2.1) と ( 式 2.2) は x 21 x + y 21 y = A 21 ( 式 3.1) x 31 x + y 31 y = A 31 ( 式 3.2) ( 式 3.1) ( 式 3.2) より x = (A 21 y 31 A 31 y 21 ) / D = B ( 式 4.1) y = (A 31 x 21 A 21 x 31 ) / D = C ( 式 4.2) ここで D = x 21 y 31 x 31 y 21 0 と仮定している D = 0 の場合 3 点 P 1, P 2, P 3 は一直線上に並ぶため 交点 P が存在する場合は 2 円の交点 ( ケース 2) として求めることが出来る ( 式 4.1) ( 式 4.2) を ( 式 1.1) に代入して整理すると z 2 = r 2 1 (x 1 B) 2 (y 1 C) 2

z 2 < 0 の時は 交点は存在しない プログラム例 // ACM ICPC2013 Domestic Problem E // http://sparth.u-aizu.ac.jp/icpc2013/d_problems.php?lang=jp#section_e // Filename: pe.c // Compile: cc -lm pe.c // Execution:./a.out < E0 > E0.result // Check: diff E0.result E0.ans #include <stdio.h> #include <math.h> #define MAX_N 10 // 杭の本数の最大値 #define MAX_R 300 // ロープの長さの最大値 // 杭のデータを表す構造体 typedef struct int x; // 杭の位置の x 座標 int y; // 杭の位置の y 座標 int r; // ロープの長さ kui_t; // 点の座標を表す構造体 typedef struct double x; double y; double z; point_t; kui_t kui[max_n]; // 杭のデータを格納する配列

int n; // 杭の本数 // 2 点間の距離を求める関数 double len(point_t p1, point_t p2) double len; len = (p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y) + (p1.z - p2.z)*(p1.z - p2.z); return sqrt(len); // 2つの杭を用いてそのロープがたるんでいない状態の最高点座標を求める関数 // そのような状態が存在しない場合は z 座標を-1 とする point_t h2(int kn1, int kn2) // kn1, kn2 = 杭番号 double d,d1; double r1,r2, h2; double r12, r22, d2; point_t p1, p2, p3; p1.x = kui[kn1].x; p1.y = kui[kn1].y; p1.z = 0; r1 = kui[kn1].r; p2.x = kui[kn2].x; p2.y = kui[kn2].y; p2.z = 0; r2 = kui[kn2].r; d = len(p1, p2); if(r1 > d+r2 r2 > d+r1 r1 + r2 < d) p3.z = -1; return p3; d2 = d*d; r12 = r1*r1; r22 = r2*r2; h2 = (-r12*r12-r22*r22-d2*d2+2*r12*r22+2*r12*d2+2*r22*d2)/(4*d2); p3.z = sqrt(h2); d1 = (r12 - r22 + d2)/(2*d); p3.x = ((d-d1)*p1.x + d1*p2.x)/d; p3.y = ((d-d1)*p1.y + d1*p2.y)/d; return p3; // 3 つの杭を用いてそのロープがたるんでいない状態の最高点座標を求める関数 // そのような状態が存在しない場合は z 座標を-1 とする point_t h3(int kn1, int kn2, int kn3) // kn1, kn2, kn3 は杭番号 point_t ans; double a1, a2, a3; double a21, a31, d; double r, x, y, z, z2; double x1, y1, r1; double x2, y2, r2;

double x3, y3, r3; double x21, y21, x31, y31; x1 = kui[kn1].x; y1 = kui[kn1].y; r1 = kui[kn1].r; a1 = r1*r1 - x1*x1 - y1*y1; x2 = kui[kn2].x; y2 = kui[kn2].y; r2 = kui[kn2].r; a2 = r2*r2 - x2*x2 - y2*y2; x3 = kui[kn3].x; y3 = kui[kn3].y; r3 = kui[kn3].r; a3 = r3*r3 - x3*x3 - y3*y3; x21 = x2 - x1; y21 = y2 - y1; x31 = x3 - x1; y31 = y3 - y1; a21 = -(a2 - a1)/2; a31 = -(a3 - a1)/2; d = x21*y31 - x31*y21; if(d!=0) x = (a21*y31 - a31*y21)/d; y = (a31*x21 - a21*x31)/d; z2 = r1*r1 - (x1 - x)*(x1 - x) - (y1 - y)*(y1 - y); if(z2 < 0) z=-1; else z = sqrt(z2); else z = -1; ans.x = x; ans.y = y; ans.z = z; return ans; // 風船の位置が点 p になりうるかをチェック // なりうる場合は 1 を返し 不可能な場合は 0 を返す // 但し 指定の杭 (k1,k2,k3) のロープの長さはチェックしない int is_ok(point_t p, int k1, int k2, int k3) int k; // 杭番号 point_t kp; // 杭の座標 double d; // 杭と p の距離 int ok=1; for(k=0; k<n; k++)

if(k==k1 k==k2 k==k3) continue; // これらの杭はチェックしない kp.x = kui[k].x; // 杭の座標をセット kp.y = kui[k].y; kp.z = 0; d = len(p, kp); // d = 点 p と杭との距離 if(d > kui[k].r) // 2 点間の距離はロープの長さより長い ok = 0; // 実現不可能 break; return ok; // ロープが一本張っている状態をチェックし 最高の高さを返す // ロープ長の最小値が 最高の高さとなる可能性がある // 可能ならそのロープ長を返し 不可能な場合は 0 を返す double r1h(void) double h; int i,k; point_t p; // ロープ長が最小の杭を求める // ロープ長が最小の杭が複数ある場合 その最小値は最高の高さにはならないので // ロープ長が最小の杭を一つだけチェックすれば良い h = MAX_R + 1; for(i=0; i<n; i++) if(kui[i].r < h) h = kui[i].r; k = i; // k = ロープ長が最小の杭番号, h = そのロープ長 p.x = kui[k].x; p.y = kui[k].y; p.z = h; // ロープが垂直に延びている場合の高さが最高 if(is_ok(p, k, k, k)) // これが実現可能ならその高さを返す return h; else // 実現不可能なら 0 を返す return 0; // ロープが二本張っている状態で 可能な最高の高さを返す // そのような状態が不可能なら 0 を返す double r2h(void) double h = 0; int i, j; point_t p; // 杭 i と杭 j からのロープが張っている状態をチェック for(i=0; i<n; i++)

for(j=i+1; j<n; j++) p = h2(i,j); // 杭 i と杭 j からのロープが張っている状態の最高点の位置 if(p.z < 0) continue; // そのような状態は存在しないので次の杭をチェック if(is_ok(p, i, j, j)) // 他の杭のロープ長も考慮してその状態が実現可能で if(p.z > h) // これまで求まっている高さよりその位置が高ければ h = p.z; // 高さの情報を更新 return h; // ロープが三本張っている状態で 可能な最高の高さを返す // そのような状態が不可能なら 0 を返す double r3h(void) int i, j, k; point_t p; double h = 0; // 杭 i,j,k からのロープが張っている状態をチェック for(i=0; i<n; i++) for(j=i+1; j<n; j++) for(k=j+1; k<n; k++) p = h3(i,j,k); // p = 杭 i,j,k からのロープが張っている位置 if(p.z == -1) continue; // そのような位置がなければ次の杭をチェック if(is_ok(p, i, j, k)) // 他の杭のロープ長も考慮してその状態が実現可能なら if(p.z > h) // これまで求まっている高さよりその位置が高ければ h = p.z; // 高さの情報を更新 return h; int main() int i,j,k,m; double max_h, h; while(1) scanf("%d n", &n); if(n==0) break; for(i=0; i<n; i++) scanf("%d %d %d n", &kui[i].x, &kui[i].y, &kui[i].r); // ロープ一本が張っている状態 // ロープ長の最小値が 最高の高さとなる可能性がある max_h = r1h(); if(max_h == 0) // ロープ 2 本が張っている状態をチェック max_h = r2h();

h = r3h(); if(h > max_h) max_h = h; printf("%.7lf n", max_h);