目录
直接调用priority_queue
JOJ 1235. Dijkstra HDU 某个题都可以通过,但是JOJ 1635. 经济出行计划只能通过90%的数据。
后来发现出错的原因是priority_queue进行push()的时候,如果有相同数据是不会进行更新heap的。同样的,如果更新数据,heap是不会进行更新的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<climits>
#include<queue>
#include<vector>
typedef long long ll;
using namespace std;
int N,M,S,E,tot,Next[2000100],head[2000100],val[2000100],edge[2000100];
ll dis[2000100];
bool visited[2000100];
void add(int x,int y,int z){
tot++;
Next[tot] = head[x];
head[x] = tot;
edge[tot] = y;
val[tot] = z;
}
struct cmp{
bool operator()(int a,int b){
return dis[a] > dis[b];
}
};
priority_queue<int,vector<int>,cmp> Q;
int main() {
cin>>N>>M;
S = 1;
E = N;
int a,b,c;
tot = 0;
memset(visited,false,sizeof(bool)*2000100);
memset(Next,0,sizeof(int)*2000100);
memset(head,0,sizeof(int)*2000100);
memset(val,0,sizeof(int)*2000100);
memset(edge,0,sizeof(int)*2000100);
for(int i = 0;i<M;i++){
cin>>a>>b>>c;
if(a==b) continue;
add(a,b,c);
add(b,a,c);
}
for(int i = 1;i<=N;i++){
dis[i] = LLONG_MAX;
}
dis[S] = 0;
Q.push(S);
while(!Q.empty()){
int t = Q.top();
Q.pop();
if(visited[t]) continue;
visited[t] = true;
for(int i = head[t];i;i = Next[i]){
if(!visited[edge[i]]&&val[i]+dis[t]<dis[edge[i]]){
dis[edge[i]] = val[i]+dis[t];
Q.push(edge[i]);
}
}
}
cout<<dis[E]<<endl;
}
采用algorithm中的push_heap()等操作
提供的操作包含:
make_heap(),push_heap(),pop_heap(),sort_heap()
注意,这里是不提供adjust_heap()的!
sort_heap()(除了这个函数都用到了)
Sort elements of heap
Sorts the elements in the heap range [first,last) into ascending order.
The elements are compared using operator< for the first version, and comp for the second, which shall be the same as used to construct the heap.
The range loses its properties as a heap.
注意参数中的Comp是实例而不是结构(和priority_queue参数不同,这是因为pq是个类,Compare结构也未实例化)
这次的修改非常懒,更改pq中元素的时候,重新建堆。毕竟调整元素并不多(?)而且建堆时间只有3N。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<climits>
#include<queue>
#include<vector>
typedef long long ll;
using namespace std;
int N,M,S,E,tot,Next[2000100],head[2000100],val[2000100],edge[2000100];
ll dis[2000100],inq[1000100]{};
bool visited[2000100];
void add(int x,int y,int z){
tot++;
Next[tot] = head[x];
head[x] = tot;
edge[tot] = y;
val[tot] = z;
}
struct cmp{
bool operator()(int a,int b){
return dis[a] > dis[b];
}
}comp;
vector<int>Q;
int main() {
cin>>N>>M;
S = 1;
E = N;
int a,b,c;
tot = 0;
memset(visited,false,sizeof(bool)*2000100);
memset(Next,0,sizeof(int)*2000100);
memset(head,0,sizeof(int)*2000100);
memset(val,0,sizeof(int)*2000100);
memset(edge,0,sizeof(int)*2000100);
for(int i = 0;i<M;i++){
cin>>a>>b>>c;
if(a==b) continue;
add(a,b,c);
add(b,a,c);
}
for(int i = 1;i<=N;i++){
dis[i] = LLONG_MAX;
}
dis[S] = 0;
Q.push_back(S);
push_heap(Q.begin(),Q.end(),comp);
inq[S] = true;
while(!Q.empty()){
int t = Q.front();
pop_heap(Q.begin(),Q.end(),comp);
Q.pop_back();
inq[t] = false;
if(visited[t]) continue;
visited[t] = true;
for(int i = head[t];i;i = Next[i]){
if(!visited[edge[i]]&&val[i]+dis[t]<dis[edge[i]]){
dis[edge[i]] = val[i]+dis[t];
if(inq[edge[i]]){
make_heap(Q.begin(),Q.end(),comp);
}
else{
Q.push_back(edge[i]);
push_heap(Q.begin(),Q.end(),comp);
inq[edge[i]] = true;
}
}
}
}
cout<<dis[E]<<endl;
}
More
这是adapter设计模式的缺陷:没有办法调用底层的函数。况且heap部分也没有提供接口可以decrease元素的值,如JOJ 1216.heap需要的那样。这其实是heap一个非常好的特性,但是compare是用户自定义的,不容易检查decrease是否合法。而且这种操作对于大多数实际上用的并不多,平衡可靠性和性能后,变成了目前heap的四个接口。
PS: decrese操作接口的实现是多么的简单:
void decrease(int i,int v){
Node* node = get(i);
node->v = node->v - v;
up(node);
}