|
|
2015/4/27(Mon) 17:15:25|NO.68802
とあるサイトで以前見かけた問題をプログラムで解きたいと思い、
hspで実装してみようと、試しに作ってみた所、if文が複雑になってしまい、
もっとわかりやすく書けないかと思い質問しました。
その問題とは
「与えられた3点を頂点とする三角形が点対称か線対称かそれ以外か調べよ」
という問題です。
この問題を次のように考えました。
点対称…三辺が等しい
線対称…二辺が等しい
よって次のように組みました。
点対称は2、線対称は1、それ以外は0が返る関数として作られています。
#module
#defcfunc check int x1,int y1,int x2,int y2,int x3,int y3
if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)=(x2-x3)*(x2-x3)+(y2-y3)*(y2-y3)=(x3-x1)*(x3-x1)+(y3-y1)*(y3-y1))and((x2-x3)*(x2-x3)+(y2-y3)*(y2-y3))and((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1)=(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) {
return 2
}
if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)=(x2-x3)*(x2-x3)+(y2-y3)*(y2-y3)=(x3-x1)*(x3-x1)+(y3-y1)*(y3-y1))or((x2-x3)*(x2-x3)+(y2-y3)*(y2-y3))or((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1)=(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) {
return 1
}
return 0
#global
もちろん、andやorでつなげているところを3重if文にすれば少しは見やすいと思いますが、
それ以外に簡単に実装する方法はありますか?
|
|
2015/4/27(Mon) 17:29:58|NO.68803
少しマクロを用いた所、少し簡単に実装できたので報告します。
#module
#define ctype kyori2(%1,%2,%3,%4) (%1-%3)*(%1-%3)+(%2-%4)*(%2-%4)
#defcfunc check int x1,int y1,int x2,int y2,int x3,int y3
if (kyori2(x1,y1,x2,y2),kyori2(x2,y2,x3,y3))and(kyori2(x2,y2,x3,y3)=kyori2(x3,y3,x1,y1))and(kyori2(x3,y3,x1,y1)=kyori2(x1,y1,x2,y2)) {
return 2
}
if (kyori2(x1,y1,x2,y2)=kyori2(x2,y2,x3,y3))or(kyori2(x2,y2,x3,y3)=kyori2(x3,y3,x1,y1))or(kyori2(x3,y3,x1,y1)=kyori2(x1,y1,x2,y2) {
return 1
}
return 0
#global
よりわかりやすく実装できるように知恵を貸してください。
|
|
2015/4/27(Mon) 17:31:40|NO.68804
一か所=となるべき場所を,にしてたようですいませんでした
|
|
2015/4/27(Mon) 18:00:43|NO.68805
強引ですが、これって大丈夫ですか
#module
#define ctype kyori2(%1,%2,%3,%4) (%1-%3)*(%1-%3)+(%2-%4)*(%2-%4)
#defcfunc check int x1,int y1,int x2,int y2,int x3,int y3
if1=(kyori2(x1,y1,x2,y2)=kyori2(x2,y2,x3,y3))
if2=(kyori2(x2,y2,x3,y3)=kyori2(x3,y3,x1,y1))
if3=(kyori2(x3,y3,x1,y1)=kyori2(x1,y1,x2,y2))
if (if1)and(if2)and(if3) {
return 2
}
if (if1)or(if2)or(if3) {
return 1
}
return 0
#global
実は、hspでもbooleanに似たようなことができるので、それを使ってみました。
|
|
2015/4/27(Mon) 18:13:26|NO.68806
動作上不具合が生じたので、
少し書き換えました。
#module
#define ctype kyori2(%1,%2,%3,%4) (%1-%3)*(%1-%3)+(%2-%4)*(%2-%4)
#define if1 (kyori2(x1,y1,x2,y2)=kyori2(x2,y2,x3,y3))
#define if2 (kyori2(x2,y2,x3,y3)=kyori2(x3,y3,x1,y1))
#define if3 (kyori2(x3,y3,x1,y1)=kyori2(x1,y1,x2,y2))
#defcfunc check int x1,int y1,int x2,int y2,int x3,int y3
if (if1)and(if2)and(if3) {
return 2
}
if (if1)or(if2)or(if3) {
return 1
}
return 0
#global
より良いプログラムになるようにアドバイスをよろしくお願いします。
|
|
2015/4/27(Mon) 18:35:02|NO.68807
先ほどちょくちょく書き込んでたものを修正してこんな感じに。
#module
#defcfunc check int x1,int y1,int x2,int y2,int x3,int y3
#define ctype d(%1,%2,%3,%4) (%1-%3)*(%1-%3)+(%2-%4)*(%2-%4)
A = d(x1,y1,x2,y2) : B = d(x2,21,x3,y3) : C = d(x3,y3,x1,y1)
return (A=B&B=C&C=A) | (A=B|B=C|C=A)
#global
三角形が点対称なら自ずと線対称でしたね。
|
|
2015/4/27(Mon) 18:40:10|NO.68808
↑のミスを修正しました。
#module
#define ctype d(%1,%2,%3,%4) (%1-%3)*(%1-%3)+(%2-%4)*(%2-%4)
#defcfunc check int x1,int y1,int x2,int y2,int x3,int y3
A = d(x1,y1,x2,y2) : B = d(x2,y2,x3,y3) : C = d(x3,y3,x1,y1)
return (A=B&B=C&C=A) + (A=B|B=C|C=A)
#global
|
|
2015/4/27(Mon) 18:48:10|NO.68809
なるほど、そのように記述することもできるんですね。
勉強になりました。
ありがとうございます。
|
|
2015/4/27(Mon) 19:03:47|NO.68810
見当違いや勘違いかも知れませんが、「点対称の三角形」というのは成立するのでしょうか…(線分?)
|
|
2015/4/27(Mon) 19:16:08|NO.68812
>774さん
言われてみればその通りですね。(何も気にせずに回答してた自分に(笑))
点対称はπrad回転で元の図形に一致することですから、三角形ではあり得ませんね。
その問題の載っていたサイトを見てみたいものです。
|
|
2015/4/28(Tue) 13:00:26|NO.68824
気になった点をいくつか。
1.引数がintである以上の情報なしに差、積をしていませんか?
(値の範囲から、オーバーフローが起きないことを確かめていますか?
2.与えられる三点が本当に三角形を形成できるかどうか判別しなくて良いのでしょうか?
(直線上に並ぶのを認める場合、大きく解釈が変わります。
3.与えられる頂点は整数上の座標を持ちます。このとき、正三角形を形成可能ですか?
不可能なら、そもそも判別する必要がなくすっきりします。
FunnyMakerさんと同じく問題を見てみたいですね、
|
|
2015/4/28(Tue) 17:33:07|NO.68829
確かに点対称ってそういう意味でしたね…。
のっていたサイトはcodeIQと記憶しています。
ひょっとしたら何か思い違いをしているかもしれません。
値の範囲のチェックや三角形が成立するかどうかを調べるひつようがありましたね
確かに整数の範囲だと正三角形ができないのでdoubleにします。
FunnyMakerさんのプログラムをもとにして、
自分なりに改造してみました。
#module
#define ctype d(%1,%2,%3,%4) (%1-%3)*(%1-%3)+(%2-%4)*(%2-%4)
#defcfunc check double x1,double y1,double x2,double y2,double x3,double y3
A = d(x1,y1,x2,y2) : B = d(x2,y2,x3,y3) : C = d(x3,y3,x1,y1)
return (A+B>C)*(B+C>A)*(A+C>B)*((A=B&B=C&C=A) + (A=B|B=C|C=A))
#global
前と同じく添削お願いします。
あとオーバーフローにならないかというのはどのように実装すれば
いいのでしょうか?
オーバーフローというのが値が大きくなりすぎることだというのは
理解しています。
|
|
2015/4/28(Tue) 17:59:04|NO.68831
不等号の向きを5行目で間違えました。
正しくは、
return (A+B<C)*(B+C<A)*(A+C<B)*((A=B&B=C&C=A) + (A=B|B=C|C=A))
です。
|
|
2015/4/28(Tue) 18:17:33|NO.68833
オーバーフローもそうですけど、丸め誤差も気になります。(この辺は計算機システムに詳しい人に譲るとして...)
ここからは正味どうでもいい話になりますが、
>整数の範囲だと正三角形ができないのでdoubleにします。
これ、今更思ったのですけどdoubleにしたところで依然として意味ないですね。
doubleといえども所詮は有限小数。
そして3点すべてが有理点であるような正三角形は存在しません(容易に証明できます)。
故に正三角形であるかどうかのチェックは不要です。
↑のことはひとまず置いておくとして...
も、
>return (A+B>C)*(B+C>A)*(A+C>B)*((A=B&B=C&C=A) + (A=B|B=C|C=A))
No.68808で私が一例として載せた方法と本質的には同じですね。
これはこれでいいと思うんですけど、
短く記述した代償として無駄な計算を行ってしまうリスクがつきまといます。
「何を目指すのか?」でやるべきことは変わってきます。
無駄な計算をなるべく減らしたいのであれば、こんなのもありますかね。
if absf(A-B) < C & C < A+B {
if A=B&B=C&C=A {
return 2
} else {
return A=B|B=C|C=A
}
} else : return 0
(※正三角形の存在云々は考慮していません)
|
|
2015/4/28(Tue) 18:53:30|NO.68837
どうせなら機能を増やせるだけ増やそうと機能を増やしてみました。
といっても正三角形の処理は消したので実質機能は増えてないと思いますが
リスクが生じるのは薄々気づいてはいたのですがやっぱり生じるんですね。
リスクについては考えずに機能を付け足しました。
/*
二等辺三角形…1
直角三角形…2
直角二等辺三角形…3
それ以外…0
*/
#module
#define ctype d(%1,%2,%3,%4) (%1-%3)*(%1-%3)+(%2-%4)*(%2-%4)
#defcfunc check double x1,double y1,double x2,double y2,double x3,double y3
A = d(x1,y1,x2,y2) : B = d(x2,y2,x3,y3) : C = d(x3,y3,x1,y1)
return (A+B<C)*(B+C<A)*(A+C<B)*((A=B|B=C|C=A)+(A*A+B*B=C*C|B*B+C*C=A*A|C*C+A*A=B*B)+((A=B|B=C|C=A)&(A*A+B*B=C*C|B*B+C*C=A*A|C*C+A*A=B*B)))
#global
returnらへんを整理する必要がありますね
添削お願いします。
こうすればリスクがなくなるというアイデアをくれる方いましたら
スクリプトの修正をお願いします。
|
|
2015/4/28(Tue) 18:59:54|NO.68838
return文を整理してみました。
前と同じくリスクは考えていません。
/*
二等辺三角形…1
直角三角形…2
直角二等辺三角形…3
それ以外…0
*/
#module
#define ctype d(%1,%2,%3,%4) (%1-%3)*(%1-%3)+(%2-%4)*(%2-%4)
#defcfunc check double x1,double y1,double x2,double y2,double x3,double y3
A = d(x1,y1,x2,y2) : B = d(x2,y2,x3,y3) : C = d(x3,y3,x1,y1)
nitouhen = (A=B|B=C|C=A) : tyokkaku = (A*A+B*B=C*C|B*B+C*C=A*A|C*C+A*A=B*B)
return (A+B<C)*(B+C<A)*(A+C<B)*(nitouhen+tyokkaku+(nitouhen&tyokkaku))
#global
添削お願いします。
|
|