题解 P5037 【抓捕】

_虹_

2018-12-22 21:48:43

Solution

刚刚看到有大佬举报这题抄袭题解这事才想起这道题。 分享一个 ~~赛后十分钟写出来的~~ **诡异**的做法 init函数预处理出所有不互质的点对。 **任意房间都有走廊相连**,所以不需要连边,只要两点互质就存在一条边,边权=出发点点权。在这张图上跑dij+heap。 ~~印象中t了。~~ 记录ans=min(ans,result[y]),在relax的时候放弃所有result[v]>=ans的点u的relax,相当于是在最短路树上剪枝。 然后AC了。 效率不如出题人题解提到的relax点y时终止dij的方法,但是这道题上慢的不多,实测后5个点慢10ms多一点。 ~~程序不吸氧总用时600ms上下。并不知道为什么会这么快。。。。不知道有没有大佬讲解一下。。。。~~ ~~rank1 31ms / 2.78MB ,不知道大佬用了什么神仙算法。orz~~ ```cpp //#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const unsigned int INT_MAX=2147483647; const int kmaxn=4500+5; const int kmaxm=kmaxn<<4; ////////////////////////////////////////////////////////////////////////////////// struct unit { int first; int second; unit():first(0),second(0){}; inline unit(const int& f,const int& s):first(f),second(s){}; const int inline operator<(const unit& u)const { return first>u.first; } }; class p_queue { unit heap[kmaxm]; int otail; public: p_queue():otail(0){}; unit inline top(){ pop_heap(&heap[0],&heap[otail]); return heap[otail-1]; } void inline pop(){--otail; } void inline push(const unit& v){ heap[otail++]=v; push_heap(&heap[0],&heap[otail]); } const bool inline empty()const{return !otail;} }q; //priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q; ///////////////////////////////////////////////////////////////////////////////// bool unable[kmaxn][kmaxn]; int result[kmaxn];//走到i点消耗的最小体力 int value[kmaxn];//从i点出发消耗掉的体力 bool hsh[kmaxn]; int otail=0; int n; int ans; int x,y; void inline relax(const int& p) { register int v=result[p]+value[p]; if(ans<=v) return; for(register int i=2;i<=n;++i) { if(!hsh[i]&&!unable[p][i]&&(result[i]<0||result[i]>v)) { result[i]=v; if(i==y) ans=v; else if(v<ans) // q.push(make_pair(v,i)); q.push(unit(v,i)); //cout<<i<<" "<<p<<endl; } } } void inline shortest_path(const int& start) { ans=INT_MAX; //q.push(make_pair(0,start)); q.push(unit(0,start)); result[start]=0; int t=0; while(!q.empty()) { t=q.top().second; q.pop(); if(!hsh[t]) { relax(t); hsh[t]=true; } } } /*void inline add_edge(const int& s,const int &d,const int &w) { if(s!=d) map[s][d]=w; }*/ inline int read(){ register int s=0,w=1; register char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w; } int t; void inline init() { for(register int i=2;i<=n;++i) { for(register int f=1;f*i<=n;++f) { value[otail++]=i*f; for(register int k=0;k<otail;++k) { unable[value[otail-1]][value[k]]=unable[value[k]][value[otail-1]]=true; } } otail=0; } } int main() { //ios::sync_with_stdio(false); //cin>>t>>n; t=read(); n=read(); init(); while(t--) { //cin>>x>>y; x=read(); y=read(); for(register int i=1;i<=n;++i) { //cin>>value[i]; value[i]=read(); result[i]=-1; hsh[i]=false; } shortest_path(x); //cout<<result[y]<<endl; printf("%d\n",result[x]); } return 0; } ``` ~~题面强调开o2,比赛时候卡了一个多小时常数都没卡过去才发觉不对。(虽然我自带大常数)~~