2/4 最短路刷题(P1144,1186,2176)
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2/4 最短路刷题(P1144,1186,2176)相关的知识,希望对你有一定的参考价值。
https://www.luogu.com.cn/problem/P1144
最短路计数:输出从结点1开始到各个点的路径数。
用到了dp记录方案的的思想:本题核心代码
for(int i=head[u];~i;i=e[i].nxt)
int v=e[i].to;
if(dist[v]>dist[u]+e[i].dis) //更新最小路径数
dist[v]=dist[u]+e[i].dis;
ans[v]=ans[u]; //若只是大于,本质上还是一条路径,只是长度加1
q.push(nodev,dist[v]);
else if(dist[v]==dist[u]+e[i].dis)
ans[v]+=ans[u]; //由于到这个点的长度相等,那么到v的方案数就要加上到u的方案数
ans[v]%=mod;
完整代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000005;
const int mod=100003;
const int inf=0x3f3f3f3f;
int n,m,head[maxn],cnt,dist[maxn],t,ans[maxn];
bool vis[maxn];
struct edge
int to,dis,nxt;
e[maxn];
void add_edge(int from,int to,int dis)
e[++cnt].to=to;
e[cnt].dis=dis;
e[cnt].nxt=head[from];
head[from]=cnt;
struct node
int pos,dis;
bool operator <(const node &x)const
return x.dis<dis;
;
void dijkstra()
priority_queue<node>q;
dist[1]=0;ans[1]=1;
q.push(node1,0);
while(!q.empty())
node cur=q.top();q.pop();
int u=cur.pos;
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];~i;i=e[i].nxt)
int v=e[i].to;
if(dist[v]>dist[u]+e[i].dis)
dist[v]=dist[u]+e[i].dis;
ans[v]=ans[u];
q.push(nodev,dist[v]);
else if(dist[v]==dist[u]+e[i].dis)
ans[v]+=ans[u];
ans[v]%=mod;
int main()
scanf("%d%d",&n,&m);
head[0]=-1;
for(int i=1;i<=n;i++)
head[i]=-1,dist[i]=inf;
for(int i=1;i<=m;i++)
int u,v;scanf("%d%d",&u,&v);
add_edge(u,v,1);add_edge(v,u,1);
dijkstra();
for(int i=1;i<=n;i++)
printf("%d\\n",ans[i]);
return 0;
https://www.luogu.com.cn/problem/P1186
三组毒瘤数据卡的我是一点办法没有,就是ac不了,最高98分,别人写的题解也大多过不去。。。
借鉴的地方:
1.
if(clock()>=995000)
//clock()函数表示运行时间,当时间过大时直接输出答案,但不能太小,否则未求出正解会WA。
cout<<ans;
return 0;
2.可标记一条边的两个点,来控制经过与否
#include<bits/stdc++.h>
using namespace std;
int n,m,fir[1005],cnt,dis[1005],x,y,ans,las[1005],nxt[1000005],val[1000005],son[1000005];
bool vis[1005],F;
inline int read()
char ch=getchar();int x=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
struct edge
int cur,val;
bool operator<(const edge &a)const
return val>a.val;
;
inline void add(int u,int v,int w)
son[++cnt]=v;
val[cnt]=w;
nxt[cnt]=fir[u];
fir[u]=cnt;
priority_queue<edge>q;
inline void dij(int s)
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
dis[s]=0;
q.push((edge)s,0);
while(!q.empty())
if(clock()>=995000)
printf("%d",ans);
exit(0);
int u=q.top().cur;q.pop();
if(vis[u]) continue;
vis[u]=true;
for(int i=fir[u];i;i=nxt[i])
if((x==son[i]&&y==u)||(x==u&&y==son[i]))continue;
if(dis[son[i]]>dis[u]+val[i])
dis[son[i]]=dis[u]+val[i];
if(!F)las[son[i]]=u;
q.push((edge)son[i],dis[son[i]]);
int main()
n=read(),m=read();
for(int i=1,u,v,w;i<=m;i++)
u=read(),v=read(),w=read();
add(u,v,w);
add(v,u,w);
dij(1);
F=true;
int f=n;
while(f)
x=f,y=las[f];
if(clock()>=995000)
cout<<ans;
return 0;
dij(1);
ans=max(dis[n],ans);
f=las[f];
printf("%d",ans);
return 0;
https://www.luogu.com.cn/problem/P2176
P2176 [USACO11DEC]RoadBlock S / [USACO14FEB]Roadblock G/S
while(p!=1)
that[++nu]=pre[p]; //pre数组记录指向的边
p=fr[p]; //fr数组记录指向的结点
int ans2=0;
for(int i=1;i<=nu;i++)
e[that[i]].dis*=2; //枚举变得距离乘2
e[that[i]^1].dis*=2;
//^1可对其反向边进行此操作,需要注意的点在于cnt不能再从1开始记录,要从2
for(int i=1;i<=n;i++)
dist[i]=inf,vis[i]=0;
ans2=max(ans2,dijkstra());
e[that[i]].dis/=2;
e[that[i]^1].dis/=2;
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
const int mod=100003;
const int inf=0x3f3f3f3f;
int n,m,head[maxn],cnt=1,dist[maxn],t,pre[maxn],flag,that[maxn],nu,fr[maxn];
bool vis[maxn];
struct edge
int to,dis,nxt;
e[maxn];
void add_edge(int from,int to,int dis)
e[++cnt].to=to;
e[cnt].dis=dis;
e[cnt].nxt=head[from];
head[from]=cnt;
struct node
int pos,dis;
bool operator <(const node &x)const
return x.dis<dis;
;
int dijkstra()
priority_queue<node>q;
dist[1]=0;
q.push(node1,0);
while(!q.empty())
node cur=q.top();q.pop();
int u=cur.pos;
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];~i;i=e[i].nxt)
int v=e[i].to;
if(dist[v]>dist[u]+e[i].dis)
dist[v]=dist[u]+e[i].dis;
if(flag==0)
pre[v]=i,fr[v]=u;
q.push(nodev,dist[v]);
return dist[n];
int main()
scanf("%d%d",&n,&m);
head[0]=-1;
for(int i=1;i<=n;i++)
head[i]=-1,dist[i]=inf;
for(int i=1;i<=m;i++)
int u,v,w;scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);add_edge(v,u,w);
int ans1=dijkstra();
//cout<<ans1<<endl;
flag=1;
int p=n;
while(p!=1)
that[++nu]=pre[p];
p=fr[p];
int ans2=0;
for(int i=1;i<=nu;i++)
e[that[i]].dis*=2;
e[that[i]^1].dis*=2;
for(int i=1;i<=n;i++)
dist[i]=inf,vis[i]=0;
ans2=max(ans2,dijkstra());
e[that[i]].dis/=2;
e[that[i]^1].dis/=2;
cout<<ans2-ans1<<endl;
return 0;
以上是关于2/4 最短路刷题(P1144,1186,2176)的主要内容,如果未能解决你的问题,请参考以下文章
最短路 P1144 最短路计数Dijkstra堆优化/SPFA