题目大意:给定一个无向图,每条边有边权,有些点有点权,一些点是加油站,求一条起点到终点的最短路,使经过有点权的点不超过k次,一管油只能走limit的时间,时间到了就只能到加油站花cost的时间加油
那个红绿灯的计算公式是 red*red/2/(red+green) 考场上很多人没推出来这个挂掉了 我推出来不会写,写了爆搜,26分
限制条件有点多。。。考虑到k<=10,加油站<=50,我们可以对k进行分层处理,将图缩点,转化成一个在加油站之间行走的图,这样k和limit的限制条件就都解除了
首先我们枚举每一个加油站(起始点和出发点看作加油站),以加油站为起点跑一遍SPFA,然后向其它加油站加长度不超过limit的直连边,这样加油站以外的点就可以去死了
然后以起始点为源再跑一遍SPFA就可以了
交的人好少好少好少。。。我这烂代码都排了第二。。因为一共就两个人交。。。
10W的SPFA跑50遍 我怕超时用了堆优化 不用堆优化可能会死 気をつけて
#include<map> #include<string> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 10100 using namespace std; map<string,int>a; string st; struct abcd{ int to,lights,next; bool usable; double f; }table[100100]; int head[M],tot,top; int n,m,k,cnt,s,t; double limit,cost,light[M]; bool is_gasonline_stand[M]; int gasonline_stands[100]; double f[M][11],ans=2147483647; pair<int,int>heap[M*10]; int pos[M][11]; void pop(); void push_up(int t); void SPFA(int from); void insert(pair<int,int>x); void add(int x,int y,double z); void Final_SPFA() { int i; memset(f,0x42,sizeof f); insert( make_pair(s,0) ); f[s][0]=0; while(top) { pair<int,int>x=heap[1];pop(); for(i=head[x.first];i;i=table[i].next) if( table[i].usable ) if( x.second+table[i].lights<=k && f[x.first][x.second]+table[i].f<f[table[i].to][x.second+table[i].lights] ) { f[table[i].to][x.second+table[i].lights]=f[x.first][x.second]+table[i].f; if( !pos[table[i].to][x.second+table[i].lights] ) insert( make_pair( table[i].to , x.second+table[i].lights ) ); else push_up( pos[table[i].to][x.second+table[i].lights] ); } } for(i=0;i<=k;i++) ans=min(ans,f[t][i]); } int main() { int i,x,y; double z,green,red; cin>>n>>m>>k>>limit>>cost; for(i=1;i<=n;i++) { cin>>st; scanf("%lf%lf",&red,&green); a[st]=++cnt; if(st=="start") s=i,gasonline_stands[++gasonline_stands[0]]=i; else if(st=="end") t=i,gasonline_stands[++gasonline_stands[0]]=i; else if( ~st.find("gas") ) is_gasonline_stand[i]=1,gasonline_stands[++gasonline_stands[0]]=i; if(red==0) light[i]=0; else light[i]=red*red/2.0/(red+green); } for(i=1;i<=m;i++) { cin>>st;x=a[st]; cin>>st;y=a[st]; cin>>st;scanf("%lf",&z); add(x,y,z); add(y,x,z); } for(i=1;i<=gasonline_stands[0];i++) SPFA(gasonline_stands[i]); Final_SPFA(); printf("%.3lf\n",ans-cost); } void add(int x,int y,double z) { table[++tot].to=y; table[tot].lights=light[x]?1:0; table[tot].f=z+light[x]; table[tot].next=head[x]; head[x]=tot; } void push_up(int t) { while( t>1 && f[heap[t].first][heap[t].second]<f[heap[t>>1].first][heap[t>>1].second] ) swap(heap[t],heap[t>>1]),swap(pos[heap[t].first][heap[t].second],pos[heap[t>>1].first][heap[t>>1].second]),t>>=1; } void insert(pair<int,int>x) { heap[++top]=x; pos[x.first][x.second]=top; push_up(top); } void pop() { pos[heap[1].first][heap[1].second]=0; heap[1]=heap[top]; heap[top--]=heap[0]; pos[heap[1].first][heap[1].second]=1; int t=2; while(t<=top) { if( t<top && f[heap[t].first][heap[t].second]>f[heap[t+1].first][heap[t+1].second] ) t++; if( f[heap[t].first][heap[t].second]<f[heap[t>>1].first][heap[t>>1].second] ) swap(heap[t],heap[t>>1]),swap(pos[heap[t].first][heap[t].second],pos[heap[t>>1].first][heap[t>>1].second]),t<<=1; else break; } } void SPFA(int from) { int i,j; memset(f,0x42,sizeof f); insert( make_pair(from,0) ); f[from][0]=0; while(top) { pair<int,int>x=heap[1];pop(); for(i=head[x.first];i;i=table[i].next) if(!table[i].usable) if( x.second+table[i].lights<=k && f[x.first][x.second]+table[i].f<f[table[i].to][x.second+table[i].lights] && f[x.first][x.second]+table[i].f<=limit ) { f[table[i].to][x.second+table[i].lights]=f[x.first][x.second]+table[i].f; if( !pos[table[i].to][x.second+table[i].lights] ) insert( make_pair( table[i].to , x.second+table[i].lights ) ); else push_up( pos[table[i].to][x.second+table[i].lights] ); } } for(i=1;i<=gasonline_stands[0];i++) { if(gasonline_stands[i]==from) continue; for(j=0;j<=k;j++) if(f[ gasonline_stands[i] ][j]<=limit) add( from , gasonline_stands[i] , f[ gasonline_stands[i] ][j]+cost ),table[tot].lights=j,table[tot].usable=1; } }