比赛(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; }