P1882 接力赛跑
CherryPockyOvO · · 题解
最近一直被机房教练逼着做多项式,被搞自闭,所以做一做水题。
结果也被水题搞自闭了
QAQ
首先先看一段本题我原来的代码
#include<cstdio>
#include<queue>
using namespace std;
int n;
queue<int> q[1000040];
bool rs[1040];
int spt[1040];
int f[1040][1040];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&spt[i],&f[i][0]);
for(int j=1;j<=f[i][0];j++) scanf("%d",&f[i][j]);
}
rs[1]=1;
q[spt[1]].push(1);
for(int i=1;n;i++){
while(!q[i].empty()){
n-=1;
int now=q[i].front();
for(int j=1;j<=f[now][0];j++){
if(rs[f[now][j]]) continue;
q[i+spt[f[now][j]]].push(f[now][j]);
rs[f[now][j]]=1;
}
q[i].pop();
}
if(n==0){
printf("%d\n",i);
break;
}
}
return 0;
}
思路清晰,就是每个时间开个queue存储该时间内到达终点牛的编号。样例更是直接水过去…………
可是一交上去全都MLE了,图片太过残忍,就不放了。
显而易见每个时间开个队列这空间必炸……(蒟蒻的我开始没想到……)
因此我们该如何优化呢,这就是优先队列登场的时候了。
这里用小根堆套个二元组,第一元素存储该编号的奶牛到终点的时间,第二个元素存储该牛的编号。
以后每次把队头取出,将这头牛该通知的牛儿全都扫一遍,没通知过的就让他策牛奔腾,向小根堆里加入一个成员,第一元素为当前时间+该牛跑一圈的时间,第二元素就是该牛的编号。
最后一次要注意,因为就剩最后一头牛,其他牛全跑过了,当最后一头牛跑完的时候,弹出,最后队列为空,输出该牛跑完的时间.
详见代码^-^
#include<cstdio>
#include<queue>
using namespace std;
int n;
bool rs[1040];
int spt[1040];
int f[1040][1040];
priority_queue<pair<int,int> > q;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&spt[i],&f[i][0]);
for(int j=1;j<=f[i][0];j++) scanf("%d",&f[i][j]);
}//读入
rs[1]=1;//对第一头牛打标记
q.push(make_pair(-spt[1],1));//注意,因为是prioity_queue是大根堆,加入时间的相反数即可实现小根堆
while(!q.empty()){
pair<int,int> now=q.top();
now.first*=-1; //因为之前加入的是时间的相反数,故要变回来。
for(int j=1;j<=f[now.second][0];j++){ //枚举当前牛要通知的所有牛。
if(rs[f[now.second][j]]) continue; //如果已经跑过了就不用跑了。
q.push(make_pair(-(now.first+spt[f[now.second][j]]),f[now.second][j])); //加入队列,再强调一遍,时间要是相反数!!!
rs[f[now.second][j]]=1; //对该牛打上标志,已经跑过.
}
q.pop();
if(q.empty()) printf("%d\n",now.first); //如果队列为空,则所有牛都跑完了,则输出最后一头牛跑完的时间
}
return 0;
}
写的比较丑,多见谅哈!