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-最短路计数

最短路计数 [LuoGu P 1144]

最短路 P1144 最短路计数Dijkstra堆优化/SPFA

最短路 P1144 最短路计数Dijkstra堆优化/SPFA

洛谷P1144——最短路计数

P1144 最短路计数 题解 最短路应用题