HDU-1006


title: HDU-1006
categories:

  • ACM
  • 盲集合求交
    tags:
  • 臨界最優
  • 屏蔽細節
    date: 2020-02-14 11:10:09

一般我們的思維都是先找第一段符合題目的解,然後找第二段第三段,從而理解題目和找出規律。但對於有些題目,規律甚至第一段的解都非常難找,但如果我們知道解位於一個臨界集合中,我們就可以不用去找這個解,轉而尋找這個臨界集合(因爲尋找解非常複雜,尋找臨界集合卻比較容易),前提是可以把解從臨界集合中分離出來(一般是臨界集合的最值)。這樣我們就可以避開尋找解這個非常複雜的過程,簡化題目。

題目

滴答和滴答

*時間限制:2000/1000 MS(Java /其他)內存限制:65536/32768 K(Java /其他)
提交總計:26354接受提交:7208
*

問題描述

時鐘的三隻指針每秒旋轉一次,並且每天相遇很多次。最後,他們對此感到無聊,並且每個人都希望遠離其他兩個人。如果一隻手與其餘任何一隻手至少有D度,那它就是快樂的。您要計算一天中所有雙手都開心的時間。

輸入值

輸入包含許多測試用例。他們每個人都有一條單行,其實數D在0和120之間(含0和120)。輸入以-1的D終止。

輸出量

對於每個D,用一行打印一天中所有手牌都高興的時間百分比,精確到小數點後3位。

樣本輸入

0
120
90
-1

樣本輸出

100.000
0.000
6.251

算法

爲什麼暴力遍歷每一秒不行

因爲本題對精度有非常高的要求,這個表應該是靜音表(掃秒錶),不會發出滴答滴答的聲音,並且要用到角速度,因爲只有這樣才能滿足精度要求

分析

本題如果仔細思考求解的話,整個過程是非常複雜的,因爲你不知道每一小段開始時究竟是那兩個針到達臨界值。既然這樣那就求臨界集合,將分針和時針從重合到再次重合看做一個大週期,將分針和錶針從重合到再次重合看做一個週期,將時針和秒針從重合到再次重合看做一個小週期。一共有三個針,C32共有三種可能,也就是說每一小段的開始時刻必然在臨界開始集合(分-時=n,秒-時=n,秒-分=n)中,並且是臨界開始集合的最大值,而每一小段的結束必然存在於臨界結束集合(分-時=360-n,秒-時=360-n,秒-分=360-n)中,並且是臨界結束集合的最小值。這樣只求兩個臨界集合就行了

代碼

#include<iostream>
#include<stdio.h>
using namespace std;
double max(double a,double b,double c){
	double max=a>b?a:b;
	return max>c?max:c;
}
double min(double a,double b,double c){
	double min=a<b?a:b;
	return min<c?min:c;
}
int main()
{		freopen("input.txt", "r", stdin);
double n;
while(cin>>n&&n!=-1){

    double maxx=12*60*60; 
    double shij=30.0/60/60;
    double fenj=6/60.0;
    double miaoj=6/1.0;
    double sfx=fenj-shij;
    double smx=miaoj-shij; 

 	double fmx=miaoj-fenj;
 	
 	double sfz=360/sfx;
 	double sfn=n/sfx;
 	double sf_n=(360-n)/sfx;
 	
 	double fmz=360/fmx;
 	double fmn=n/fmx;
 	double fm_n=(360-n)/fmx;
 	
 	double smz=360/smx;
 	double smn=n/smx;
 	double sm_n=(360-n)/smx;
 	
 	double shichang=0;
 	for(double i=0;i<=maxx;i+=sfz)
 	{
 		for(double j=0;j<=maxx;j+=fmz)
 		{
 			if(j+fm_n<i+sfn) continue;
 			if(i+sf_n<j+fmn) break;
 			for(double k=0;k<=maxx;k+=smz)
 			{
 				if(k+sm_n<i+sfn||k+sm_n<j+fmn) continue;
 				if(j+fm_n<k+smn||i+sf_n<k+smn) break;
 				double kaishi=max(i+sfn,j+fmn,k+smn);
 				double jieshu=min(i+sf_n,j+fm_n,k+sm_n);
 				if(jieshu>kaishi)
 				shichang+=jieshu-kaishi;
 			}
 		}
 		
 	}
 	printf("%.3f\n",100.0*shichang/maxx);
 }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章