HDU - 6026 - Deleting Edges - (最短路径spfa)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6026

题意:有一个n个节点的无向图,节点标记为0~n-1,边长的范围是[0,9],现在希望删除这个图中的一些边,使得这个图变为一个有n-1条边的树,并且对于此树中的每一个节点v,它到0节点的距离与原图中点v与点0之间的最短路径值相同,用矩阵给出原图中任意两点间边的长度,问有多少种方法得到此树。

解析:先用spfa求出所有点到点0的最短路径,然后枚举每一点求出从0点经过中间点i到点j的路径数in[j],且此路径要与原图中0点到j点的最短路径长度相同,那么总的方案数就是in[1]*in[2]*...in[n-1] , 因为每个点都从in[i]条间接路径中选择一条留下其余删掉方案数就是in[i],总的方案数就是in[i]乘起来。

注意:in[i]也包括了0点和点i之间直接有边相连的情况。

原理大概是,在上面删除过程进行完毕之后,每条边的"前面节点",也就是必须经过前面节点才能到达0节点,这样的话每个点只关系但一条由"前面节点"过来的边,n个节点共n条边,但是0节点没有"前面节点"也就没有对应的边,所以共n-1条边 。

代码:

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
typedef long long ll;
#define M 55
const int inf=0x3f3f3f3f;
const int mod=1e9+7;

int n,in[M],dis[M],vis[M],Map[M][M];
char str[M][M];

void init()
{
    memset(in,0,sizeof(in));
    memset(Map,0,sizeof(Map));
}
void spfa()
{
    memset(vis,0,sizeof(vis));
    for(int i=0;i<=n;i++) dis[i]=inf;
    queue<int>Q;
    Q.push(0);
    dis[0]=0;
    vis[0]=1;
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        vis[u]=0;
        for(int i=0;i<n;i++)
        {
            if(!Map[u][i]) continue;
            int v=Map[u][i];
            if(dis[i]>=dis[u]+v)
            {
                dis[i]=dis[u]+v;
                if(!vis[i])
                {
                    vis[i]=1;
                    Q.push(i);
                }
            }
        }
    }
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=0;i<n;i++)
        {
            scanf("%s",str[i]);
            for(int j=0;j<n;j++)
            {
                if(i==j) continue;
                Map[i][j]=Map[j][i]=str[i][j]-'0';
            }
        }
        spfa();
        for(int i=0;i<n;i++)     //i是0到j的中间点
        {
            for(int j=0;j<n;j++)//计算in[j]
            {
                if(i!=j&&dis[j]==dis[i]+Map[i][j]&&Map[i][j]) in[j]++;
            }
        }
        ll sum=1;
        for(int i=1;i<n;i++)
        {
            sum=(sum*in[i])%mod;
        }
        printf("%lld\n",sum);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sdau20163942/article/details/80103551