zoukankan      html  css  js  c++  java
  • 有关最短路计数的问题

    想必大家都会求最短路吧,这里就不再多说了;

    我看有很多人在一顿套模板,什么dijkstra,SPFA等等,这是可以的;

    但身为OIer,思路要开阔对不对?

    首先我们注意到,我们可以利用bfs来求每个点的深度。因为在所有边边权为1的时候,点的深度就是点的最短距离;

    这样在写法上便少了队列优化SPFA中退栈时还要把标记抹除这一操作,会大大提高算法速度;

    在bfs的时候,我们不仅仅要从一个点的父亲继承最短路,还要继承方案数;

    有个细节,起点的方案数要记为1;

    #include <bits/stdc++.h>
    #define int long long
    #define p 100003
    using namespace std;
    struct littlestar{
    	int to;
    	int nxt;
    }star[4000010];
    int head[4000010],cnt;
    inline void add(register int u,register int v)
    {
    	star[++cnt].to=v;
    	star[cnt].nxt=head[u];
    	head[u]=cnt;
    }
    int n,m;
    long long g[1000010];
    int dis[1000010],vis[1000010];
    queue<int> q;
    int st,ed;
    inline void bfs(register int s)
    {
    	memset(g,0,sizeof(g));
    	memset(dis,0x3f,sizeof(dis));
    	q.push(s);
    	dis[s]=0;
    	vis[s]=1;
    	g[s]=1;
    	while(q.size()){
    		register int u=q.front();
    		q.pop();
    		for(register int i=head[u];i;i=star[i].nxt){
    			register int v=star[i].to;
    			if(dis[v]==dis[u]+1) g[v]=(g[u]+g[v])%p;
    			if(vis[v]) continue;
    			vis[v]=1;
    			dis[v]=dis[u]+1;
    			g[v]=g[u]%p;
    			q.push(v);
    		}
    	}
    }
    signed main()
    {
    	scanf("%lld%lld",&n,&m);
    	for(register int i=1;i<=m;i++){
    		register int u,v;
    		scanf("%lld%lld",&u,&v);
    		add(u,v);
    		add(v,u);
    	}
    	bfs(1);
    	for(int i=1;i<=n;i++){
    		printf("%lld
    ",g[i]);
    	}
    }
    

    有闲时间的读者可以看一下这道题的扩展:

    一张N*M的无向图,有k个特殊的点;你从1号点出发,必须停留且只停留在一个特殊点休息一段时间,然后到达n号点;(可以一次经过多个特殊点,但如果在不同的特殊点停留休息,就算不同种方案);求符合条件的**最短路**的**方案数**;

    其实这道题稍加思考就可以得到正解:分别从1号点和n号点bfs()求出每个点到1号点和n号点的最短路及最短路下的方案数;我们根据乘法原理把最短路下的方案数乘起来就可以了;

    #include <bits/stdc++.h>
    #define int long long
    #define p 1000000007
    using namespace std;
    struct littlestar{
    	int to;
    	int nxt;
    }star[8000010];
    int head[8000010],cnt;
    void add(int u,int v)
    {
    	star[++cnt].to=v;
    	star[cnt].nxt=head[u];
    	head[u]=cnt;
    }
    int n,m;
    char s[1010][1010];
    int query[1010][1010];
    long long g[1000010];
    int water[1000010];
    int dis[1000010],vis[1000010];
    queue<int> q;
    int st,ed;
    void bfs(int s)
    {
    	memset(g,0,sizeof(g));
    	memset(dis,0x3f,sizeof(dis));
    	q.push(s);
    	dis[s]=0;
    	vis[s]=1;
    	g[s]=1;
    	while(q.size()){
    		int u=q.front();
    		q.pop();
    		for(int i=head[u];i;i=star[i].nxt){
    			int v=star[i].to;
    			if(dis[v]==dis[u]+1) g[v]=(g[u]+g[v])%p;
    			if(vis[v]) continue;
    			vis[v]=1;
    			dis[v]=dis[u]+1;
    			g[v]=g[u]%p;
    			q.push(v);
    		}
    	}
    }
    int stdis[1000010];
    long long stg[1000010];
    signed main()
    {
    	scanf("%lld%lld",&n,&m);
    	int num=0;
    	for(register int i=1;i<=n;i++){
    		for(register int j=1;j<=m;j++){
    			query[i][j]=++num;
    		}
    	}
    	for(register int i=1;i<=n;i++){
    		scanf("%s",s[i]+1);
    	}	
    	for(register int i=1;i<=n;i++){
    		for(register int j=1;j<=m;j++){
    			if(s[i][j]=='@') st=query[i][j];
    			if(s[i][j]=='#') ed=query[i][j];
    			if(s[i][j]=='*') water[++water[0]]=query[i][j];
    			if(s[i][j]=='X') continue;
    			if(i-1>0&&s[i-1][j]!='X'){
    				add(query[i][j],query[i-1][j]);
    			}
    			if(j-1>0&&s[i][j-1]!='X'){
    				add(query[i][j],query[i][j-1]);
    			}
    			if(i+1<=n&&s[i+1][j]!='X'){
    				add(query[i][j],query[i+1][j]);
    			}
    			if(j+1<=m&&s[i][j+1]!='X'){
    				add(query[i][j],query[i][j+1]);
    			}
    		}
    	}
    	bfs(st);
    	for(int i=1;i<=num;i++) stdis[i]=dis[i],stg[i]=g[i];
    	memset(vis,0,sizeof(vis));
    	bfs(ed);
    	int ans=INT_MAX;
    	for(int i=1;i<=water[0];i++){
    		ans=min(ans,stdis[water[i]]+dis[water[i]]);
    	}
    	long long fians=0;
    	for(int i=1;i<=water[0];i++){
    		if(stdis[water[i]]+dis[water[i]]==ans){
    			fians=(fians+stg[water[i]]*g[water[i]]%p)%p;
    		}
    	}
    	if(ans==INT_MAX){
    		cout<<"-1 0";
    		return 0;
    	}
    	cout<<ans<<" "<<fians;
    }
    /*
    3 3
    @..
    .*.
    *.#
    
    
    
    4 4
    @...
    ....
    ....
    ...#
    
    */
    
  • 相关阅读:
    网络流,再出发!
    2SAT
    并查集
    最大密度子图
    网络流提高专题(洛谷题单)
    JQuery 操作 ListBox间移动和ListBox内移动
    关于多表Update和Delete的应用
    XML格式与DataTable、DataSet、DataView格式的转换
    FCKeditor配置和精简
    点击fileupload后button事件不起作用
  • 原文地址:https://www.cnblogs.com/kamimxr/p/11623080.html
Copyright © 2011-2022 走看看