CH6202 黑暗城堡(最短路径生成树)

版权声明:本文为博主原创文章,未经博主允许不得转载,除非先点了赞。 https://blog.csdn.net/A_Bright_CH/article/details/82909245

题目

在顺利攻破Lord lsp的防线之后,lqr一行人来到了Lord lsp的城堡下方。Lord lsp黑化之后虽然拥有了强大的超能力,能够用意念力制造建筑物,但是智商水平却没怎么增加。现在lqr已经搞清楚黑暗城堡有N个房间 (1≤N≤1000),M条可以制造的双向通道,以及每条通道的长度。
lqr深知Lord lsp的想法,为了避免每次都要琢磨两个房间之间的最短路径,Lord lsp一定会把城堡修建成树形的;但是,为了尽量提高自己的移动效率,Lord lsp一定会使得城堡满足下面的条件:设 D[i] 为如果所有的通道都被修建,第 i 号房间与第1号房间的最短路径长度;而 S[i] 为实际修建的树形城堡中第 i 号房间与第1号房间的路径长度;要求对于所有整数 i(1≤i≤N),有 S[i]=D[i] 成立。
为了打败Lord lsp,lqr想知道有多少种不同的城堡修建方案。于是lqr向applepi提出了这个问题。因为applepi还要忙着出模拟赛,所以这个任务就交给你了。当然,你只需要输出答案对 2^31–1 取模之后的结果就行了。

题解

最短路径生成树
每个点的d[i]显然是一个固定值,我们可以先跑一遍dijkstra得到每个点的d。
接下来就考虑计数了。
我们把每个点按d[i]递增排序,这么做的目的是让计数有顺序,因为每个距离远的可以从距离近的转移过来,所以要先遍历距离近的点。遍历过的节点加入集合T,未遍历的存在集合S。接下来每次从集合S中拿出一个点,加入集合T,如果它有cnt中方案满足d[y]=d[x]+edge(x,y)(x\in T,y\in S),将它们累乘即是答案。
因为我们能够保证T集合中的点都是可以用最短距离达到的,我们随意接在一个点的后面,使得新加入的点也具有了s[i]=d[i]的性质。这些方案都可以计入答案。
最后抛出博主的一个问题:排序真的有用吗?我把排序去掉,并把第二个for改成1~n也过了数据。求大神解释~

代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const ll mod=(1ll<<31)-1;
const int maxn=1010,maxm=500000;

int n,m;

struct E{int y,c,next;}e[maxm*2];int len=0,last[maxn];
void ins(int x,int y,int c)
{
    e[++len]=(E){y,c,last[x]};last[x]=len;
}

int d[maxn];bool v[maxn];
priority_queue<pii,vector<pii>,greater<pii> > q;
void dijkstra()
{
    memset(d,63,sizeof(d));d[1]=0;
    q.push(make_pair(0,1));
    while(!q.empty())
    {
        int x=q.top().second;q.pop();//debug pop
        if(v[x]) continue;
        v[x]=true;
        for(int k=last[x];k;k=e[k].next)
        {
            int y=e[k].y;
            if(d[y]>d[x]+e[k].c)
            {
                d[y]=d[x]+e[k].c;
                q.push(make_pair(d[y],y));
            }
        }
    }
}

int id[maxn];
bool cmp(int i1,int i2)
{
    return d[i1]<d[i2];
}

int ma[maxn][maxn];
int main()
{
    memset(ma,63,sizeof(ma));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y,c;
        scanf("%d%d%d",&x,&y,&c);
        ma[x][y]=ma[y][x]=c;
        ins(x,y,c);ins(y,x,c);
    }
    
    dijkstra();
    
    for(int i=1;i<=n;i++) id[i]=i;
    sort(id+1,id+n+1,cmp);
    ll ans=1,cnt;
    for(int i=2;i<=n;i++)//debug ans=0乘法初始化为1 
    {
        cnt=0;
        for(int j=i-1;j>=1;j--)
        {
            if(d[id[i]]==d[id[j]]+ma[id[i]][id[j]]) cnt++;//debug 反了 
        }
        ans=ans*cnt%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/A_Bright_CH/article/details/82909245