1486:黑暗城堡

【题目描述】

知道黑暗城堡有 N 个房间,M 条可以制造的双向通道,以及每条通道的长度。

城堡是树形的并且满足下面的条件:

设 Di 为如果所有的通道都被修建,第 i号房间与第 1 号房间的最短路径长度;

而 SiSi 为实际修建的树形城堡中第 i 号房间与第 1 号房间的路径长度;

要求对于所有整数 i(1≤i≤N) ,有 Si=Di 成立。

你想知道有多少种不同的城堡修建方案。当然,你只需要输出答案对 231−1231−1 取模之后的结果就行了。

【输入】
第一行为两个由空格隔开的整数 N,MN,M ;

第二行到第 M+1行为 3 个由空格隔开的整数 x,y,l :表示 x 号房间与 y 号房间之间的通道长度为 l 。

【输出】
一个整数:不同的城堡修建方案数对 231−1231−1 取模之后的结果。

【输入样例】
4 6
1 2 1
1 3 2
1 4 3
2 3 1
2 4 2
3 4 1
【输出样例】
题意是让你统计以1为源点的最短路径树的方案数。

思路:先求出 以1为原点的最短路 d[ ] 数组。然后按d数组从小到大排序求方案数,然后模拟求最短路的过程 按乘法原理统计方案数。

述 时间复杂度 ,当n数据范围在大点肯定TLE,我们可以发现,双重循环寻找方案的过程其实类似于dijkstra求最短路的过程,只不过那个三角不等式换成了 等于号,所以我们依旧可以用堆 来优化这个过程然后使得复杂度降为。

AC Code:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
 
typedef long long ll;
 
const int maxn=1010;
const ll nil=(long long)1<<40-1;
#define mod ((1<<31)-1)
 
struct my{
       int v,next;
       ll w;
};
 
struct lmjer{
       int v;
       ll w;
};
 
struct node{
       int u;
       ll w;
       bool operator<(const node &rhs)const{
            return w>rhs.w;
       }
};
 
int fa,adj[maxn],n,m;
ll tu[maxn][maxn];
lmjer d[maxn];
bool done[maxn];
priority_queue<node>Q;
my bian[maxn*maxn];
 
void myinsert(int u,int v,ll w){
     bian[++fa].v=v;
     bian[fa].next=adj[u];
     bian[fa].w=w;
     adj[u]=fa;
}
 
void dijkstra(int s){
     for (int i=1;i<=n;i++) d[i].w=nil,d[i].v=i;
     d[s].w=0;
     node x;
     x.u=s;
     x.w=0;
     Q.push(x);
     while(!Q.empty()){
        x=Q.top();Q.pop();
        int u=x.u;
        if(done[u]) continue;
        done[u]=true;
        for (int i=adj[u];i;i=bian[i].next){
            int v=bian[i].v;
            if(d[v].w>d[u].w+bian[i].w){
                d[v].w=d[u].w+bian[i].w;
                x.u=v;
                x.w=d[v].w;
                Q.push(x);
            }
        }
     }
}
 
bool cmp(const lmjer a,const lmjer b){
     return a.w<b.w;
}
 
int main(){
    scanf("%d%d",&n,&m);
    memset(tu,10,sizeof(tu));
    int u,v;
    ll w;
    for (int i=1;i<=m;i++){
        scanf("%d%d%lld",&u,&v,&w);
        myinsert(u,v,w);
        myinsert(v,u,w);
        tu[u][v]=tu[v][u]=min(tu[u][v],w);
    }
    dijkstra(1);
    sort(d+1,d+1+n,cmp);
    int ans=1;
    for (int i=2;i<=n;i++){
            ll temp=0;
        for (int j=1;j<i;j++){
            int x=d[i].v,y=d[j].v;
            if(d[i].w==d[j].w+tu[x][y]) temp++;
        }
    ans=(long long)ans*temp%mod;
    }
    printf("%d\n",ans);
return 0;
}

题库地址:http://ybt.ssoier.cn:8088/problem_show.php?pid=1486

posted @ 2022-05-11 19:58  学c++的小学生  阅读(150)  评论(0编辑  收藏  举报