Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.9.174] |
|
Сообщ.
#1
,
|
|
|
Please,people!!!
Пусть даны целые числа h,m(часы,минуты), 0<=h<=11, 0<=m<=59, определяющие время суток. Опредилить наименьшее время(число полных минут), к-е должно пройти до того момента,когда часовая и минутная стрелки на цферблате: а)совпадут; b)расположатся перпендикулярно друг другу; ВНИМАНИЕ!!! !!!МОЖНО ИСПОЛЬЗОВАТЬ ТОЛЬКО ОПЕРАТОР ПРИСВАИВАНИЯ И ВВОДА/ВЫВОДА!!! |
Сообщ.
#2
,
|
|
|
Теория такова:
Представь себе циферблат с двумя стрелками. У каждой стрелки есть свой угол, в отношении с начальным положением (там где цифра 12). 12 1 |--/ | / 2 | / |/ o И каждая стрелка с каждым тиком изменяют этот угол по разному: к примеру минутная стрелка изменяет угол с каждым движением на 360/60 градусов, а часовая на 360/12 градусов. В то-же время есть взаимоотношение, что каждый тик часовой стрелки, это 60 тиков минутной, тоесть в каждые 360/12 градусов часовой стрелки входит 360 градусов минутной (полный оборот или 60 тиков). Следовательно с каждым движением минутной стрелки на 360/60 градусов часовая стрелка делает движение на (360/12)/60 градусов. Посчитав всё это можно определить, что часовая стрелка изменяет своё положение на пол градуса в каждый тик минутной стрелки (за одну минуту). Рассмотрим теперь твою первую задачу: Пусть у нас даны исходный час - H и исходные минуты - M. Найдём такое количество минут - DeltaM, при добавлении которых исходному времени углы часовой и минутной стрелки совпали бы. Для этого составим следующее уравнение: 0.5*(H*60+M+DeltaM)=6*(M+DeltaM) В этом уравнении нам неизвестна только искомая DeltaM. С левой стороны уравнения выражен угол часовой стрелки, посчитанный из общего количества минут умноженных на изменение угла часовой стрелки за каждую минуту. С правой стороны уравнения выражен угол минутной стрелки, без учёта часов, так как минутная стрелка совпадёт с часовой хотябы один раз за час (тоесть меньше чем за час). Теперь выразим из уравнения искомую DeltaM: Умножим обе стороны на 2: H*60+M+DeltaM=12*M+12*DeltaM Перенесём DeltaM в левую сторону уравнения, а всё остальное в правую: DeltaM-12*DeltaM=-H*60-M+12*M -11*DeltaM=-H*60+11*M Поменяем знаки уравнения: 11*DeltaM=H*60-11*M Разделим обе части на 11: DeltaM=(H*60-11*M)/11 DeltaM=H*60/11-M DeltaM и будет разницей между заданным временем, и временем, когда часовая и минутная стрелки совпадут. Рассмотрим теперь твою вторую задачу: В этой задаче у нас углы часовой и минутной стрелки должны отличаться на 90 градусов в любую сторону (минутная левее, или правее). Следовательно уравнение почти такое же, за исключением того, что надо учесть разницу в градусах в любую сторону: abs(6*(M+DeltaM)-0.5*(H*60+M+DeltaM))=90 Здесь из угла минутной стрелки вычитается угол часовой, и разница по модулю должна быть равна 90 градусам. Как и в прошлый раз, умножим обе стороны на 2: abs(12*M+12*DeltaM-H*60-M-DeltaM)=180 abs(11*DeltaM+11*M-H*60)=180 Далее уравнение раскладывается на два пути: 11*DeltaM+11*M-H*60=180 и 11*DeltaM+11*M-H*60=-180 DeltaM=(180+H*60)/11-M и DeltaM=(H*60-180)/11-M Получится так, что решения должны совпасть, но быть различными в знаках (По моему, но я могу и ошибаться). Как эту задачу сделать без оператора условия я не знаю )) |
Сообщ.
#3
,
|
|
|
А вот вариант как сделать задачку #2 без оперетора условия.
Вникать, что там Some1 написал не охота, поэтому получаем код, на основе его рассуждений. var result1,result2,result,m,h:longint; begin readln(h,m); result1:=(180+H*60)/11-M; {а может быть и так: result1:=abs((180+H*60)/11-M)}; result2:=DeltaM=(H*60-180)/11-M; {аналогично} result:=result1*byte(result1<result2)+result2*byte(result2<=result1); writeln(result); end. Т.е. выражение byte(100<200) равно единице, а выражение byte(5<>5) равно нулю. Это и позволяет найти минимальное значение. |
Сообщ.
#4
,
|
|
|
Не, я так тоже делать умею, тока я не думаю, что у него препод такой зверь ))
Я как то своему в универе так "оптимизировал прогу" в 10 местах, он меня послал подальше с моими оптимизациями ))) Пришлось переделывать. ИМХО - Должен быть другой способ, возможно я где-то ошибся или выбрал не тот метод )))) |
Сообщ.
#5
,
|
|
|
Ну вы мужики понаписали!
Что за байты у вас в выражениях? Ничего не понимаю! Объясните поподробнее что это за byte такой и с чем его едят! |
Сообщ.
#6
,
|
|
|
Byte -тип такой - целые числа от 0 до 255 - занимает 1 байт. А в данном случае используется приведение типа boolean к этому типу.
|
Сообщ.
#7
,
|
|
|
Поясню полнее то, что сказал Ozzy:
Вот смотри, когда ты пишешь if <чёнить> then <ченить ещё> то там, где <чёнить> ты всегда пишешь переменную типа boolean - тоесть условие. Любое условие в паскале рассматривается как переменная типа boolean. Этот тип может иметь только два значения -True или False. В первом случае условие - правда, а во втором случае - неправда. Вот пример: Если мы напишем (100<500) - то это правда. И следовательно паскаль воспримет всё это выражение как переменную типа boolean, равную true. Если мы теперь напишем if (100<500)=true then <Чёнить>, то наше условие выполнится, и выполнится <чёнить> А если написать if (100<500)=false then <Чёнить>, то мы получим расхождение, и условие не выполнится, и не выполнится наше <чёнить>. Теперь смотри дальше - внутренне в паскале тип Boolean занимает один байт в памяти, и является по сути байтом, у которого 0 - это неправда (False в паскале) и 1 - это правда (True в паскале). В паскале есть такое хорошее свойство - приведение типов, при помощи него можно узнать, чему равен байт переменной типа Boolean, если взять эту переменную в скобки и перед ней написать byte. byte(1<10) будет равен 1 так как 1 действительно меньше 10 и значит наш Boolean=True и в его байте содержится 1. byte(1>10) будет равен 0 так как 1>10 это неправда и значит наш Boolean=Falseи в его байте содержится 0. Если написать write(byte(100<500)) на экран выведется "1". Всё это удобно для использования условий прямо в операторах присваивания. Ведь если умножать на "0" то получится "0", а если умножать на "1" то получится то число, которое мы на "1" умножали )) Смотри, тебе написали: result:=result1*byte(result1<result2)+result2*byte(result2<=result1); Если result1<result2 это правда, то первый byte будет равен 1, а второй 0, и тогда result1 будет умножен на 1, а result2 на 0, в результате чего он сократится, и result будет равен result1. Если же result1<result2 это неправда, то первый byte будет равен 0, а второй 1, и тогда result1 будет умножен на 0 и сократится, а result2 на 1 и result будет равен result2. Таким образом вся эта запись является аналогом такой: If (result1<result2)=true then result:=result1 else result:=result2; |
Сообщ.
#8
,
|
|
|
Some1, большое тебе спасибо!
Теперь всё хорошо ясно! |
Сообщ.
#9
,
|
|
|
Люди! Нашёл в задаче а ужасный баг( b пока не смотрел)!
В результате проги мы находим просто кол-во минут до времени , в к-е стрелки совпадут. Т.е. ответ в некоторых случаях получается отрицательным! А нам надо найти кол-во минут до ближайшего момента когда стрелки совпадут, отсчитывая этот момент с заданного времени! Люди у кого какие идеи? Может другой алгоритм предложите (хотя и этот хорош - только где то, что-то нужно подправить)? |
Сообщ.
#10
,
|
|
|
А почему ты в "Алгоритмы" не напишешь?
Текущее положение стрелок (будем считать по большим цифрам, т.е. значения = 0..12): h = h mod 12 Hpos = h + m/60 - позиция часовой стрелки Mpos = m/5 - позиция минутной стрелки Теперь... если Mpos < Hpos, значит минутная стрелка находится раньше часовой (относительно 12 часов), и они совпадут в этом часе. Если же Mpos > Hpos, значит позже, и они совпадут в следующем часе. [*] В первом случае: h + m/60 = m/5 h = m*11/60 Msovpadut = h*60/11 Minterval = Msovpadut - m [*] Во втором случае: h = (h + 1) mod 12 h + m/60 = m/5 h = m*11/60 Msovpadut = h*60/11 Minterval = 60 + Msovpadut - m Это теория... попробуй... (то, что синим прогать не надо - это вывод формулы ) |
Сообщ.
#11
,
|
|
|
Во! Вроде работает! ;D
Var h, m: Integer; Hpos, Mpos, Msovp, Mint: Real; Begin Write('Введите Часы Минуты: '); ReadLn(h, m); h := h mod 12; Hpos := h + m/60; Mpos := m/5; If Mpos < Hpos then Begin Msovp := h*60/11; Mint := Msovp - m End else If Mpos > Hpos then Begin h := (h + 1) mod 12; Msovp := h*60/11; Mint := 60 + Msovp - m End; WriteLn('Через ', Trunc(Mint), ' минут ', Trunc(Frac(Mint)*60), ' секунд') End. |
Сообщ.
#12
,
|
|
|
To Jin-X: Жека, прочитай внимательно последнюю строку условия (первого поста) ))
To .exe: Ты часом условие не подправлял ? ) А то мне кажется, там писалось, что надо найти время (без "которое должно пройти") до совпадения стрелок, кажется автоматически подумал, что не важно, в какую сторону время считать )) Короче тогда делай, как сказал Jin-X ) З.Ы. Жек, у тебя точно правильно ? А какой наименьший шаг у твоей часовой стрелки?? Не размером ли с пять минут ?... я что-то сегодня не очень соображаю )) (ну в смысле у тебя не берётся за правило, что часовая стрелка делает одно движение в пять минут, и исходя из этого высчитывается угол ?) Я могу ошибаться |
Сообщ.
#13
,
|
|
|
Нет, не в 5 минут... Если она на 13 минутах, то будет 2.6
Ну если учесть последнюю строку условия, тогда так: Var h, m: Integer; Hpos, Mpos, Msovp, Mint: Real; After: Boolean; Begin Write('Введите Часы Минуты: '); ReadLn(h, m); h := h mod 12; Hpos := h + m/60; Mpos := m/5; After := Mpos > Hpos; h := (h + Ord(After)) mod 12; Msovp := h*60/11; Mint := 60*Ord(After) + Msovp - m; WriteLn('Через ', Trunc(Mint), ' минут ', Trunc(Frac(Mint)*60), ' секунд') End. P.S. Что, собственно, однохренственно ;D |
Сообщ.
#14
,
|
|
|
Мужики, я уж извиняюсь, но как эту задачу можно сделать, если мало того, что оператор условия не дают использовать, так ещё и булевские переменные не разрешают?
|
Сообщ.
#15
,
|
|
|
Ужас.......
А промежуточные булевские можно ? Ну без объявления самой переменной, ну как у меня выше.. я не объявлял булевскую, а только в присваиваниях писал булевское условие. Это тоже нельзя ? |
Сообщ.
#16
,
|
|
|
Ну хорошо!!!
Var h, m: Integer; Hpos, Mpos, Msovp, Mint: Real; Begin Write('Введите Часы Минуты: '); ReadLn(h, m); h := h mod 12; Hpos := h + m/60; Mpos := m/5; h := (h + Ord(Mpos > Hpos)) mod 12; Msovp := h*60/11; Mint := 60*Ord(Mpos > Hpos) + Msovp - m; WriteLn('Через ', Trunc(Mint), ' минут ', Trunc(Frac(Mint)*60), ' секунд') End. Булевских переменных нет! (есть только булевские выражения, но это же не переменные) ;D |
Сообщ.
#17
,
|
|
|
Сформулировал не полностью - булевские выражения тоже низззя !!!! ???
|
Сообщ.
#18
,
|
|
|
Наверное, что-то вроде этого:
program clock1; var h,m,s,t:integer; begin readln(h,m); s:=((m-5*h-(m div 12)) div abs(m-5*h-(m div 12))+1) div 2; (* s=0, если минутная стрелка позади часовой, иначе s=1 *) t:=(60-m)*s; h:=h+s; m:=m*(1-s); t:=t+5*h-m+(h-1) div 2; writeln(t); end. |
Сообщ.
#19
,
|
|
|
А лучше - вроде этого:
program clock2; var h,m,s,t:integer; begin readln(h,m); t:=5*h-m+(h-1) div 2; s:=((t div abs(t))+1) div 2; t:=t+65*(1-s); writeln(t); end. |
Сообщ.
#20
,
|
|
|
Кто-нибудь, пож-ста, поясните последнее решение!
|
Сообщ.
#21
,
|
|
|
to exe смотри вроде так
programm cl; var z,j,h,m:integer; begin readln(h,m); j:=h*5 div m; if j=0 then writeln('Svpodaet'); if m:=h*5+30 then writeln('perpendikylarni!'); end. |
Сообщ.
#22
,
|
|
|
извини я условие мельком прочитал!!!
|