比赛(Floyd / dfs)
第3题 比赛 查看测评数据信息
N 头奶牛,编号 1∼N,一起参加比赛。奶牛的战斗力两两不同。这些奶牛之间已经进行了 M 轮两两对决。在对决中,战斗力高的奶牛一定会战胜战斗力低的奶牛。请问,通过上述 M 轮对决的结果,可以确定多少头奶牛的具体战斗力排名。1≤N≤100 ,1≤M≤4500,数据保证合法。
输入格式
第一行包含两个整数 N,M。
接下来 M 行,每行包含两个整数 a,b,表示奶牛 a 和奶牛 b 之间进行了对决,并且奶牛 a 战胜了奶牛 b。
输出格式
输出可以确定具体战斗力排名的奶牛数量。
输入/输出例子1
输入:
5 5
4 3
4 2
3 2
1 2
2 5
输出:
2
样例解释
2 号奶牛输给了 1,3,4 号奶牛,战胜了 5 号奶牛,可以确定它的战斗力排名为 4。
5 号奶牛输给了排在第 4 的 2 号奶牛,所以它的战斗力排名为 5。
其它奶牛不确定。
第一个思路是,找点的入度出度(遍历),如果入度+出度-1(减去自己)==n,那就可以确定
入度 => 这头奶牛被打败了(注意“被”字), 出度 => 这头奶牛打败了其它奶牛
N - 1 => 除了这只奶牛之外的其它奶牛;
#include <bits/stdc++.h>
using namespace std;
int n, m, t1, t2, vis[105], vis2[105], cnt=0, cnt2=0, ans=0;
vector<int>a[105], a1[105];
void dfs(int now)
{
if (vis[now]==1) return ;
vis[now]=1;
cnt++;
for (int i=0; i<a[now].size(); i++)
dfs(a[now][i]);
}
void dfs2(int now)
{
if (vis2[now]==1) return ;
vis2[now]=1;
cnt2++;
for (int i=0; i<a1[now].size(); i++)
dfs2(a1[now][i]);
}
int main()
{
scanf("%d%d", &n, &m);
for (int i=1; i<=m; i++)
{
scanf("%d%d", &t1, &t2);
a[t1].push_back(t2);
a1[t2].push_back(t1);
}
for (int i=1; i<=n; i++)
{
cnt=0, cnt2=0;
memset(vis, 0, sizeof(vis));
memset(vis2, 0, sizeof(vis2));
dfs(i);
dfs2(i);
//printf("%d %d\n", cnt, cnt2);
if (cnt+cnt2-1==n) ans++;
}
printf("%d", ans);
return 0;
}
第二个思路是floyd
floyd不仅能求任意两点的最短路,还能求一个点能否到另一个点。
程序流程:
先跑Floyd,(跑Floyd可以明确所有点之间的关系(即使是间接到达的))
然后再统计每个点的入、出度,查每个点,假设符合上面说的式子,ans++
#include <bits/stdc++.h>
using namespace std;
const int N=1e3+5;
int n, m, u1, v1, dis[N][N], ans=0;//dis[x][y]表示x,y是否连通
void flo()
{
for (int k=1; k<=n; k++)
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++)
dis[i][j]=dis[i][j] || (dis[i][k] && dis[k][j]); //核心,意思要么是dis[i][j]中间本来就联通,或者从i到k并且从k到j都联通,如果两种情况都不是,就不连通
}
int main()
{
scanf("%d%d", &n, &m);
for (int i=1; i<=m; i++)
{
scanf("%d%d", &u1, &v1);
dis[u1][v1]=1; //输入时将dis[x][y]赋值为真
}
flo();
for (int i=1; i<=n; i++)
{
int s=0;
for (int j=1; j<=n; j++)
if (dis[i][j] || dis[j][i]) s++; //有相连
if (s==n-1) ans++; //排除自身这个点
}
printf("%d", ans);
return 0;
}

浙公网安备 33010602011771号