题目连接: http://acm.pku.edu.cn/JudgeOnline/problem?id=1167
题目大意:
一男子于12:00来到一个公交车站,他记录下了12:00-12:59所有公交车的到站情况。现在我们假设:
1) 同一条线路的公交车到站是有规律的,也就是每隔一个固定时间就会有一辆车到站。
2) 公交车的到站是以分钟为最小计量单位的。
3) 每一条线路的车至少到站两次。
4) 经过该车站的公交车线路≤17条。
5) 不同线路的公交车可以同时到达该车站。
6) 不同线路的公交车到该车站的时刻和时间间隔均可以相同。
现在问,根据该男子的记录,最少有多少条公交车线路经过该车站?
由题意可以推出的结论:
first<ing;
ing<=59-first;
=>0<=firist<=29;
frist+(time-1)*ing<=59;
frist+time*ing>59;
2<=ing<=59;
所以,59-frist<time*ing<=59+ing-first;=>time=1+(59-firist)/ing;
其中n是在0~59中,最多有几趟改线路的车经过。。。。。
在每一种first的取值的情况下,有相对应的多少种线路,枚举为:59+57+。。。。。。+1=(60)*30/2=900,种线路,这是首先必须预处理的,因为我们要处理出每一种线路的能在(0~59)经过该站的最多,那么经过次数最多且满足条件的情况下,肯定改线路是一定,次数越多能从剩余的数列中删去数越多,那么余下的线路也会尽可能的少。。
题词初看了很久,没有一点点想法,看了下官方的解报告,晕。。英文的解题报告还真是难看。。。。明白的大概的算法,然后到网上搜了一个人的解题报告看了一下,才有自己的想法。。。
官方和网上牛人的算法,他们提及的两个重点:一个是搜索的顺序和剪枝估价函数;我试了下放宽估价函数的限制,把>=改成> TLE了。。。
官方的解题报告:http://olympiads.win.tue.nl/ioi/ioi94/contest/day2prb2/solution.html
#include<cmath> #include<iostream> #include<stdio.h> #include<algorithm> using namespace std; const int MAXM=910; const int MAXN=310; int num[MAXN],visit[MAXN]; struct node { int first; int ing; int time; bool operator<(const node &a) const { return time>a.time; } }route[MAXM]; int n,logicR,res,Min; inline bool check(int first,int ing) { if(!visit[first]) return false; if(first+ing>=60||!visit[first+ing]) return false; if(first>=ing) return false; for(int i=first;i<=59;i+=ing) if(!visit[i]) return false; return true; } inline void shift(int index,int flag) { for(int i=route[index].first;i<=59;i+=route[index].ing) visit[i]+=flag,res+=flag; } void dfs(int p,int now) { if(res==0) { Min=min(Min,now); return ; } int i=p; for(;i<logicR&&route[i].time>res;i++); for(;i<logicR;i++) { int t=(res-1)/route[i].time; if(t+now>=Min) return ; //剪枝的估价函数。。。。。 if(check(route[i].first,route[i].ing)) { shift(i,-1); dfs(i,now+1); shift(i,1); } } } int main() { cout<<pow(4.0,9)<<endl; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",num+i); visit[num[i]]++; } logicR=0; //0<=fist<ing; //ing<=59-frist; // 0<=first<=29; 枚举所有符合题意的线路。。 for(int i=0;i<=29;i++) { if(!visit[i]) continue; for(int j=i+1;j<=59-i;j++) { if(check(i,j)) { route[logicR].first=i; route[logicR].ing=j; route[logicR++].time=1+(59-i)/j; } } } sort(route,route+logicR); //确定搜索的顺序 res=n,Min=17; dfs(0,0); printf("%d/n",Min); return 0; }