问题描述
某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路。
现在,大臣们帮国王拟了一个修高速公路的计划。看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能。如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对。
国王想知道,在大臣们给他的计划中,有多少个便利城市对。
输入格式
输入的第一行包含两个整数n, m,分别表示城市和单向高速公路的数量。
接下来m行,每行两个整数a, b,表示城市a有一条单向的高速公路连向城市b。
输出格式
输出一行,包含一个整数,表示便利城市对的数量。
样例输入
5 5
1 2
2 3
3 4
4 2
3 5
样例输出
3
样例说明
城市间的连接如图所示。有3个便利城市对,它们分别是(2, 3), (2, 4), (3, 4),请注意(2, 3)和(3, 2)看成同一个便利城市对。
评测用例规模与约定
前30%的评测用例满足1 ≤ n ≤ 100, 1 ≤ m ≤ 1000;
前60%的评测用例满足1 ≤ n ≤ 1000, 1 ≤ m ≤ 10000;
所有评测用例满足1 ≤ n ≤ 10000, 1 ≤ m ≤ 100000。
本题是判断有向图中两个相互连通的点的对数,刚开始做的时候没学连通分量的算法,自己夏姬八推了一个结果连样例都没有过,只好爆搜了,对每个点dfs,用一个mp二维数组来保存一个点是否能到达另一个点,mp[i][j]==1代表i能到达j,就这样搜过了百分之六十,后来做完后去网上学了taijan算法,发现这道题就是tarjan板子题,直接套用tarjan,最后对每个强连通分量求一个组合数即可。
暴力dfs60分代码:
#include
#include
#include
#define rep(i,x,n) for(int i=x;i
#define per(i,x,n) for(int i=n-1;i>=x;i--)
using namespace std;
//head
typedef long long ll;
int n,m,a,b,cur;
short mp[10001][10001];
int head[10006],vis[10006];
struct Edge{int to,next;}edge[100006];
void addedge(){edge[cur].to=b;edge[cur].next=head[a];head[a]=cur++;}
ll bfs()
{
ll cnt=0;
queue<int>q;
rep(i,1,n+1)
{
memset(vis,0,sizeof(vis));
q.push(i);vis[i]=1;
while(!q.empty())
{
int x=q.front();q.pop();
for(int j=head[x];j!=-1;j=edge[j].next)
{
int nx=edge[j].to;
if(!vis[nx])
{
q.push(nx);vis[nx]=1;mp[i][nx]=1;
if(mp[i][nx]==1&&mp[nx][i]==1)cnt++;
}
}
}
}
return cnt;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
memset(head,-1,sizeof(head));
cin>>n>>m;
rep(i,0,m)cin>>a>>b,addedge();
cout<return 0;
}
tarjan算法满分代码:
#include
#include
#include
#define rep(i,x,n) for(int i=x;i
using namespace std;
int n, m, a, b, cnt, cur = 0, tot = 0, ans=0,head[10006], low[10006], dfn[10006],vis[10006];
struct Edge {
int to, next;
} edge[100006];
void addedge() {
edge[cur].to = b;
edge[cur].next = head[a];
head[a] = cur++;
}
stack<int>q;
int tarjan(int x) {
low[x] = dfn[x] = ++tot;
q.push(x);vis[x]=1;
for(int i = head[x]; i != -1; i = edge[i].next) {
int nx = edge[i].to;
if(!dfn[nx]) {
tarjan(nx);
low[x] = min(low[x], low[nx]);
} else if(vis[nx])
low[x] = min(low[x], dfn[nx]);
}
if(low[x]==dfn[x])
{
cnt=0;
while(1)
{
int tmp=q.top();
q.pop();
vis[tmp]=0;
++cnt;
if(tmp==x)break;
}
if(cnt>1)ans+=(cnt*(cnt-1)/2);
}
}
int main() {
memset(head, -1, sizeof(head));
cin >> n >> m;
rep(i, 0, m)cin >> a >> b, addedge();
rep(i,1,n+1)if(!dfn[i])tarjan(i);
cout << ans << endl;
}
版权声明:本文为原创文章,转载请标明出处。
https://blog.csdn.net/u014390156