Owen_codeisking @ 2018-07-25 10:29:40
为什么重载运算符改成make_pair就好了?没改的话
戳这
这是改进前的代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m,s;
struct Edge
{
ll to,v,next;
}e[500010];
ll tot,dis[500010],head[500010],vis[500010];
struct cmp
{
bool operator()(ll a,ll b){
return dis[a]>dis[b];
}
};
priority_queue<ll,vector<ll>,cmp> pq;
void Link(ll x,ll y,ll w){
e[++tot].to=y;
e[tot].v=w;
e[tot].next=head[x];
head[x]=tot;
}
void Dijsktra(){
ll u,v;
pq.push(s);
while(!pq.empty()){
u=pq.top(),pq.pop();
if(vis[u]) continue;
vis[u]=1;
for(ll i=head[u];i;i=e[i].next){
v=e[i].to;
if(dis[v]>dis[u]+e[i].v){
dis[v]=dis[u]+e[i].v;
pq.push(v);
}
}
}
}
int main()
{
/*freopen("testdata.in","r",stdin);
freopen("testdata.out","w",stdout);*/
scanf("%lld%lld%lld",&n,&m,&s);
for(ll i=1;i<=m;i++){
ll x,y,w;
scanf("%lld%lld%lld",&x,&y,&w);
Link(x,y,w);
}
for(ll i=1;i<=n;i++)
dis[i]=2147483647;
dis[s]=0;
Dijsktra();
for(ll i=1;i<n;i++)
printf("%lld ",dis[i]);
printf("%lld\n",dis[n]);
return 0;
}
这是改进后的代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m,s;
struct Edge
{
ll to,v,next;
}e[500010];
ll tot,dis[500010],head[500010],vis[500010];
priority_queue< pair<int,int> > pq;
void Link(ll x,ll y,ll w){
e[++tot].to=y;
e[tot].v=w;
e[tot].next=head[x];
head[x]=tot;
}
void Dijsktra(){
ll u,v;
pq.push(make_pair(0,s));
while(!pq.empty()){
u=pq.top().second;pq.pop();
if(vis[u]) {
continue;
}
vis[u]=1;
for(ll i=head[u];i;i=e[i].next){
v=e[i].to;
if(dis[v]>dis[u]+e[i].v){
dis[v]=dis[u]+e[i].v;
pq.push(make_pair(-dis[v],v));
}
}
}
}
int main()
{
/*freopen("testdata.in","r",stdin);
freopen("testdata.out","w",stdout);*/
scanf("%lld%lld%lld",&n,&m,&s);
for(ll i=1;i<=m;i++){
ll x,y,w;
scanf("%lld%lld%lld",&x,&y,&w);
Link(x,y,w);
}
for(ll i=1;i<=n;i++)
dis[i]=1e10;
dis[s]=0;
Dijsktra();
for(ll i=1;i<n;i++)
printf("%lld ",dis[i]);
printf("%lld\n",dis[n]);
return 0;
}
这是题解
#include<bits/stdc++.h>
#define M(x,y) make_pair(x,y)
using namespace std;
int fr[100010],to[200010],nex[200010],v[200010],tl,d[100010];
bool b[100010];
void add(int x,int y,int w){
to[++tl]=y;
v[tl]=w;
nex[tl]=fr[x];
fr[x]=tl;
}
priority_queue< pair<int,int> > q;
int main(){
int n,m,x,y,z,s;
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
for(int i=1;i<=n;i++) d[i]=1e10;
d[s]=0;
q.push(M(0,s));
while(!q.empty()){
int x=q.top().second;
q.pop();
if(b[x]) continue;
b[x]=1;
for(int i=fr[x];i;i=nex[i]){
int y=to[i],l=v[i];
if(d[y]>d[x]+l){
d[y]=d[x]+l;
q.push(M(-d[y],y));//懒得重载运算符
}
}
}
for(int i=1;i<=n;i++) printf("%d ",d[i]);
return 0;
}
by SuperJvRuo @ 2018-07-25 10:50:42
priority_queue的内部实现是二叉堆,第一份代码里,dis改变后无法保证堆的性质,很可能炸掉
by Owen_codeisking @ 2018-07-25 15:27:11
@ACdreamer 这么搞笑。。。
by Owen_codeisking @ 2018-07-25 15:28:30
辣鸡 operator
by GKxx @ 2018-07-25 16:11:23
不是operator的锅吧。本来就应该用pair吧
by GKxx @ 2018-07-25 16:18:16
operator跟make_pair本身没有任何关系。第一份代码是你写得有问题。我一般都是这样写
struct CmpType {
bool operator()(const std::pair<int, int>& lhs, const std::pair<int, int>& rhs) {
return lhs.second > rhs.second;
}
};
然后
std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int> >, CmpType> pq;
那么priority_queue就会按照pair的第二关键字构造最小堆(我习惯first是节点编号,second是对应的dist),从而你每次从pq中取出的都是dist值最小的pair。
题解不重载运算符是因为他把dist取了相反数,并且first是dist而second是结点编号,pair的默认小于运算符是first为第一关键字,second为第二关键字,那么它就会按照dist的相反数构造“最大堆”,也就是按照dist构造最小堆了,殊途同归。
by GKxx @ 2018-07-25 16:28:36
按照你第一份代码那样写,意味着队列里的元素的优先级是由外界的dist变化决定的,priority_queue就无法实时保证队列里的元素满足堆性质了。我只要在外面随便改一改dist的值,priority_queue就废了