JZOJ 3808. 【NOIP2014模拟8.25】道路值守

12 篇文章 0 订阅
10 篇文章 0 订阅

Description

Crossbell 自治州有着四通八达的现代化交通。时值独立庆典之际,随着来自周边国家旅客的日益增
多,犯罪行为也悄无声息开始滋长起来。
特别任务支援科的警察们从总部收到了关于调查伪装在游客中的犯罪分子的请求。通过调查,他们
得到了一张地图,记载了 Crossbell 自治州内每一条道路的长度。
显然,为了减少犯罪行为被发现的可能性,犯罪分子总是会选择最短的路径来行动。为了方便安排
人手和推测犯罪分子采取的路线,他们希望得知任意两个地点之间,有多少条犯罪分子可能会选择的道
路。

Input

第一行,包含两个整数N;M,表示Crossbell 内的地点数和道路数。
接下来N 行,每行包含三个整数xi; yi; li,表示道路连接的两个不同地点的标号,以及道路的长度。
道路是双向的。
两个不同地点之间不会有超过一条道路。

Output

输出一行,包含N(N -11)/2 个整数C1,2;C1,3; : : : ;C1,N ;C2,3;C2,4; : : : ;C2,N ; : : : ;CN-1,N。
其中Cx,y 表示x 号地点到y 号地点之间有多少条犯罪分子可能会选择的道路。

Sample Input

5 6
1 2 1
2 3 1
3 4 1
4 1 1
2 4 2
4 5 4

Sample Output

1 4 1 2 1 5 6 1 2 1

Data Constraint

• 对于分值为30 的子任务1,保证 N<=50
• 对于分值为30 的子任务2,保证 N<=100
• 对于分值为40 的子任务3,保证 N<=500

Solution

  • 这题解法显然,5秒钟的时限保证了不会卡常!

  • 首先枚举枚举每一个点作为源点,对于这个点做一次SPFA(单源最短路)

  • 同时记录每个点到源点的最短路径,这样是 O(N2)

  • 之后枚举按题目要求的每一个源点之外的点,往回走

  • 中途标记每条走过的边,这样还是 O(N2)

  • 所以加上第一层的枚举,总的时间复杂度是 O(N3) 的,成功碾过~

Code

#include<cstdio>
#include<cstring>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=501;
int n,m,x,y,z,ans;
int b[N][N];
int que[3*N],f[N],g[N][N];
int bz[N],p[N];
inline void spfa(int x)
{
    int l=f[que[1]=x]=0,r=1;
    while(l<r)
    {
        int k=que[++l];
        bz[k]=false;
        for(int i=1;i<=n;i++)
            if(b[k][i]!=b[0][0])
                if(f[k]+b[k][i]<f[i])
                {
                    f[i]=f[k]+b[k][i];
                    g[i][g[i][0]=1]=k;
                    if(!bz[i]) bz[que[++r]=i]=true;
                }else
                    if(f[k]+b[k][i]==f[i]) g[i][++g[i][0]]=k;
    }
}
inline void dfs(int x,int y)
{
    p[x]=true;
    for(int i=1;i<=g[x][0];i++)
    {
        int k=g[x][i];
        ans++;
        if(k!=y && !p[k]) dfs(k,x);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    clr(b,43);
    for(int i=1,x,y,z;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        b[x][y]=b[y][x]=z;
    }
    for(int i=1;i<n;i++)
    {
        clr(f,43),clr(g,0);
        spfa(i);    
        for(int j=i+1;j<=n;j++)
        {
            clr(p,ans=0);
            dfs(j,0);
            printf("%d ",ans);
        }
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值