HDU 3191 How Many Paths Are There(含0权边的次短路计数)
题目传送门
题目大意
求\(DAG\)的次短路长度及次短路条数\((3\leq n\leq 50)\),顶点从\(0\)开始标号。
Solution
次短路计数模板题
但有个坑点是存在\(0\)权边,比如边\(A-B\)的边权为\(0\),那么\(A\)必须在\(B\)出堆之前出堆,这样可以保证用\(B\)来松弛其他点时,\(A\)的贡献已经计算在内。
所以先进行拓扑排序
在优先队列中当节点距离相同时比较其拓扑序即可。
一定要注意顶点是从\(0\)开始标号的\(!!!\)
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
int head[55],to[5005],nxt[5005],w[5005],cnt=0;//数组要开够
int in[55],dfn[55];
int n,m,s,t;
int d[55][2],vis[55][2],num[55][2];
struct node{
int d,x,flag;
node(int d,int x,int flag):d(d),x(x),flag(flag){}
bool operator < (const node& a)const{
return d>a.d?1:(d==a.d?dfn[x]>dfn[a.x]:0);//距离相同时比较拓扑序
}
};
void add(int u,int v,int ww){
nxt[++cnt]=head[u];
to[cnt]=v;
w[cnt]=ww;
head[u]=cnt;
}
void topo(){
int cnt2=0;
queue<int>q;
memset(dfn,0,sizeof(dfn));
for(int i=0;i<n;++i){//顶点是从0开始标号的
if(!in[i]){
dfn[i]=++cnt2;
q.push(i);
}
}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i!=-1;i=nxt[i]){
int v=to[i];
in[v]--;
if(!in[v]){
dfn[v]=++cnt2;
q.push(v);
}
}
}
}
void dij(int s,int t){
memset(d,INF,sizeof(d));
memset(num,0,sizeof(num));
memset(vis,0,sizeof(vis));
priority_queue<node>q;
d[s][0]=0;
num[s][0]=1;
q.push(node(0,s,0));
while(!q.empty()){
int u=q.top().x,flag=q.top().flag;
q.pop();
if(vis[u][flag])continue;
vis[u][flag]=1;
for(int i=head[u];i!=-1;i=nxt[i]){
int v=to[i],temp=d[u][flag]+w[i];
if(d[v][0]>temp){
if(d[v][0]!=INF){
d[v][1]=d[v][0];
num[v][1]=num[v][0];
q.push(node(d[v][1],v,1));
}
d[v][0]=temp;
num[v][0]=num[u][flag];
q.push(node(d[v][0],v,0));
}else if(d[v][0]==temp){
num[v][0]+=num[u][flag];
}else if(d[v][1]>temp){
d[v][1]=temp;
num[v][1]=num[u][flag];
q.push(node(d[v][1],v,1));
}else if(d[v][1]==temp){
num[v][1]+=num[u][flag];
}
}
}
}
int main(){
int u,v,ww;
while(scanf("%d%d%d%d",&n,&m,&s,&t)!=EOF){
cnt=0;//cnt记得重置为0
memset(head,-1,sizeof(head));
memset(in,0,sizeof(in));
for(int i=1;i<=m;++i){
scanf("%d%d%d",&u,&v,&ww);
add(u,v,ww);
in[v]++;
}
topo();
dij(s,t);
printf("%d %d\n",d[t][1],num[t][1]);
}
return 0;
}

浙公网安备 33010602011771号