洛谷P1144最短路计数(堆优化dij+记忆化搜索)

题目链接:传送门
题意:就是求无向图起点为1到其他点的最短路的条数。
思路:求解最短路采用堆优化dij(当然也可以采用spfa),最短路条数可以用记忆化搜索,用数组dp[i]记录起点到i点的最短路数目,如果从u点又找到一条到达i点的最短路,那么dp[i]=dp[i]+dp[u],因为起点1到u点的最短路可能有多条,因此需要加上,然后继续从u点搜索下去。初始化起点dp[1]=1;
最短路数目也可以直接开一个sum数组记录答案,当又找到一条从u点到i点的最短路,那么sum[i]+=sum[u]即可,当发现比当前的最短路更短时候,更新一下即可。
代码:

#include
using namespace std;
const int maxn=1e6+5;
const int maxm=2e6+5;
const int INF=0x3f3f3f3f;
#define mod 100003
int dis[maxn],head[maxn],dp[maxn];
bool vis[maxn];
int cnt,n,m;
int sum[maxn];
struct node
{
    int en,next,len;
}edge[maxm*2];
struct node1
{
    int id,len;
    node1(int id1=0,int len1=0)//C++构造点的编号和边长度
    {
        id=id1;
        len=len1;
    }
    friend bool operator<(node1 x,node1 y)//优先队列()自定义优先级
    {
        return x.len>y.len;
    }
};
void add(int u,int v,int w)
{
    edge[cnt].en=v;
    edge[cnt].len=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void init()
{
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(dp,0,sizeof(dp));
    memset(sum,0,sizeof(sum));
}
void dij(int st)
{
    for(int i=1;i<=n;i++)
    {
        vis[i]=false;
        dis[i]=INF;
    }
    dis[st]=0;
    priority_queue<node1>q;
    q.push(node1(st,0));
    while(!q.empty())
    {
        node1 now=q.top();
        q.pop();
        if(vis[now.id]) continue;
        vis[now.id]=true;
        for(int i=head[now.id];~i;i=edge[i].next)
        {
            int en=edge[i].en;
            int len=edge[i].len;
            if(!vis[en]&&(dis[en]>dis[now.id]+len))
            {
                dis[en]=dis[now.id]+len;
                q.push(node1(en,dis[en]));
                sum[en]=sum[now.id];
            }
            else if(dis[en]==dis[now.id]+len) sum[en]=(sum[en]+sum[now.id])%mod;
        }
    }
}
int dfs(int x)//记忆化搜索
{
    if(dp[x]) return dp[x];
    for(int i=head[x];~i;i=edge[i].next)
    {
        int v=edge[i].en;
        if(dis[v]+1==dis[x])//这里无权图,直接加1,带权的加上edge[i].len判断即可
        {
            dp[x]=(dp[x]+dfs(v))%mod;
        }
    }
    return dp[x];
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v,1);
            add(v,u,1);
        }
        sum[1]=1;
        dij(1);
        /*
        dp[1]=1;
        for(int i=1;i<=n;i++)//记忆化搜索输出答案
        {
            printf("%d\n",dfs(i));
        }*/
        for(int i=1;i<=n;i++)//利用sum数组记录答案
        {
            printf("%d\n",sum[i]%mod);
        }
    }
    return 0;
}

你可能感兴趣的:(数据结构,ACM,OJ)