原题链接
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(1≤n≤2000)个点m(1≤m≤5000)m(1\le m\le 5000)m(1≤m≤5000)条边的有向图,求按照错误的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;
}

286

被折叠的 条评论
为什么被折叠?



