【题目描述】
某国有 N 个编号为 1 至 N 的城市和 M 条编号为 1 至 M 的公路。
第 i 条公路是从城市 Ai通往城市 Bi的单向道路。
Tom 正在计划他的暑假旅程,他可以从某些城市出发,经过零条或多条道路旅行,最后 到达某些城市。
有多少对城市可以成为 Tom 旅程的起点和终点?我们以不同的顺序区分是否为同一对 城市。比如(2,3)和(3,2)属于不同的 2 对。
【数据范围】
第一行输入两个整数 N(2≤N≤2000)和 M(0≤N≤min(2000,N(N-1)))。 接下来有 M 行,每行有 2 个整数 Ai和 Bi(1≤Ai,Bi≤N;Ai≠Bi),表示从 Ai到 Bi有一条 单向道路。输入的所有数对(Ai,Bi)都不相同。
Floyd主要是求解图的连通和最短路的问题,和迪杰斯特拉和SPFA不同(我都搞忘了,还是要复习啊),后两个是求单源最短路,而Floyd是求图中每个点到其他点的最短路,这是不同于后两个的地方,但是Floyd算法时间复杂度极高,可达O(),只可用于小范围数据
下面是Floyd 25/100的“高分”代码
#include<bits/stdc++.h>
using namespace std;
int f[2005][2002];
int n,m,ans;
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
f[a][b]=1;
}
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
f[i][j]=f[i][j]||(f[i][k]&f[k][j]);
}
}
}
for(int i=1;i<=n;i++)//枚举起点
for(int j=1;j<=n;j++)//枚举终点
{
if(f[i][j]) ans++;
}
ans+=m//自己可以同时作为起点和终点
cout<<ans;
return 0;
}
Floyd虽然是可行的,但是限于本题题目数据限制,只能另寻它法
其实,可以用简单的DFS遍历整个图,用循环枚举每个点作为起点,换成单源问题求连通,这样已转化就不难了
每次枚举完一个起点就统计一次
附上AC正解代码
#include<bits/stdc++.h>
using namespace std;
const int N=10050;
int first[N],nex[N],to[N],tot;
int n,m;
int ans;
bool p[N];
void add(int x,int y)
{
nex[++tot]=first[x];
first[x]=tot;
to[tot]=y;
}
void find(int x)
{
p[x]=true;//走过的标记
for(int e=first[x];e;e=nex[e])//枚举由x出发的边
{
int y=to[e];
if(p[y]) continue;
find(y);
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
add(a,b);//建立a到b的有向图
}
for(int i=1;i<=n;i++)
{
memset(p,0,sizeof(p));//每次循环要把标记全部清零
find(i);//i做起点
for(int j=1;j<=n;j++)
{
ans+=p[j];
}
}
cout<<ans;
return 0;
}
还是要多练习啊