2021牛客多校#7 J-xay loves Floyd

原题链接
				https://ac.nowcoder.com/acm/contest/11258/J

题目大意

有人将Floyd算法写错成一下形式:

for i from 1 to n
	for j from 1 to n
		for k from 1 to n
			dis[i][j] <- min(dis[i][j] , d[i][k] + dis[k][j])

给定n(1≤n≤2000)n(1\le n\le 2000)n(1n2000)个点m(1≤m≤5000)m(1\le m\le 5000)m(1m5000)条边的有向图,求按照错误的Floyd算法执行后,有多少dis[i][j]dis[i][j]dis[i][j]和正确的算法结果一样。

题解

如果我们直接用Floyd算法进行计算的话,复杂度为O(n3)O(n^3)O(n3),肯定是不行的。

再想想其他计算最短路的算法,还有dijkstradijkstradijkstra算法,复杂度为O(m×logn)O(m\times log_n)O(m×logn),所以我们用dijkstradijkstradijkstra算出正确答案。

再考虑如何算错误答案,由于知识储备量有限,我实在找不出算错误答案的算法,所以我们只能通过错误代码进行剪枝操作进行优化。

参考代码

#include<bits/stdc++.h>
#define FOR(i,n,m) for(int i=n;i<=m;i++)
#define For(i,n,m) for(int i=n;i>=m;i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
using namespace std;
const int N=2e3+5;
const int inf=0x3f3f3f3f;
int n,m,ans=0;
int f[N][N],di[N][N],dis[N],vis[N],g[N][N];
struct node
{
    int v,w;
    node (int v=0,int w=0):v(v),w(w){}
    friend bool operator < (const node &a,const node &b){return a.w>b.w;}
};
vector<node> v[N];
void dij(int s)
{
    FOR(i,1,n)vis[i]=0,dis[i]=inf;
    dis[s]=0;
    priority_queue<node> q;
    q.push(node(s,dis[s]));
    while(!q.empty())
    {
        int u=q.top().v;q.pop();
        vis[u]=1;
        if(v[u].empty())continue;
        FOR(i,0,v[u].size()-1)
        {
            int v1=v[u][i].v,w1=v[u][i].w;
            if(vis[v1])continue;
            if(dis[v1]>dis[u]+w1){dis[v1]=dis[u]+w1;q.push(node(v1,dis[v1]));}
        }
    }
    FOR(i,1,n)di[s][i]=dis[i];
}
int main()
{
    scanf("%d%d",&n,&m);
    FOR(i,1,n)
        FOR(j,1,n)
            f[i][j]=inf,f[i][i]=0;
    FOR(i,1,m)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        v[x].pb(node(y,z));
        g[x][y]=1;
        f[x][y]=z;
    }
    FOR(i,1,n)dij(i);
    FOR(i,1,n)
        if(!v[i].empty())
        FOR(j,1,n)
        {
            if(f[i][j]==di[i][j]||di[i][j]==inf||i==j)continue;
            FOR(k,0,v[i].size()-1)
            {
                int v1=v[i][k].v;
                f[i][j]=min(f[i][j],f[i][v1]+f[v1][j]);
            }
            if(f[i][j]==di[i][j])v[i].pb(node(j,f[i][j]));
        }
    FOR(i,1,n)
        FOR(j,1,n)
            if(f[i][j]==di[i][j])ans++;
    cout<<ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值