Floyd 判斷連通性
d[i][j]僅表示i,j之間是否聯通
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]);
有向圖和無向圖都適用
當然了,也可以DFS判斷連通性
裸題:
P2419 [USACO08JAN]牛大賽Cow Contest
題目背景
[Usaco2008 Jan]
題目描述
N (1 ≤ N ≤ 100) cows, conveniently numbered 1..N, are participating in a programming contest. As we all know, some cows code better than others. Each cow has a certain constant skill rating that is unique among the competitors.
The contest is conducted in several head-to-head rounds, each between two cows. If cow A has a greater skill level than cow B (1 ≤ A ≤ N; 1 ≤ B ≤ N; A ≠ B), then cow A will always beat cow B.
Farmer John is trying to rank the cows by skill level. Given a list the results of M (1 ≤ M ≤ 4,500) two-cow rounds, determine the number of cows whose ranks can be precisely determined from the results. It is guaranteed that the results of the rounds will not be contradictory.
FJ的N(1 <= N <= 100)頭奶牛們最近參加了場程序設計競賽:)。在賽場上,奶牛們按1..N依次編號。每頭奶牛的編程能力不盡相同,並且沒有哪兩頭奶牛的水平不相上下,也就是說,奶牛們的編程能力有明確的排名。 整個比賽被分成了若干輪,每一輪是兩頭指定編號的奶牛的對決。如果編號為A的奶牛的編程能力強於編號為B的奶牛(1 <= A <= N; 1 <= B <= N; A != B) ,那么她們的對決中,編號為A的奶牛總是能勝出。 FJ想知道奶牛們編程能力的具體排名,於是他找來了奶牛們所有 M(1 <= M <= 4,500)輪比賽的結果,希望你能根據這些信息,推斷出盡可能多的奶牛的編程能力排名。比賽結果保證不會自相矛盾。
輸入輸出格式
輸入格式:
第1行: 2個用空格隔開的整數:N 和 M
第2..M+1行: 每行為2個用空格隔開的整數A、B,描述了參加某一輪比賽的奶 牛的編號,以及結果(編號為A,即為每行的第一個數的奶牛為 勝者)
輸出格式:
第1行: 輸出1個整數,表示排名可以確定的奶牛的數目
輸入輸出樣例
說明
輸出說明:
編號為2的奶牛輸給了編號為1、3、4的奶牛,也就是說她的水平比這3頭奶
牛都差。而編號為5的奶牛又輸在了她的手下,也就是說,她的水平比編號為5的
奶牛強一些。於是,編號為2的奶牛的排名必然為第4,編號為5的奶牛的水平必
然最差。其他3頭奶牛的排名仍無法確定。
#include<cstdio> #include<iostream> #include<cstring> #include<bits/stdc++.h> using namespace std; void read(int &x){ char ch=getchar();x=0;int flg=1; if(ch=='-') flg=-1; for(;ch<'0'||ch>'9';) ch=getchar(); for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=flg; } int n,m,d[105][105],ans; int main() { read(n);read(m); for(int i=1;i<=m;i++){ int u,v; read(u);read(v); d[u][v]=1; }for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ d[i][j]=d[i][j]|d[i][k]&d[k][j]; } } } for(int i=1;i<=n;i++){ int tp=0; for(int j=1;j<=n;j++){ if(d[i][j]==1||d[j][i]==1) ++tp; }if(tp==n-1) ++ans; }cout<<ans; return 0; }
最小環問題
最小環就是指在一張圖中找出一個環,使得這個環上的各條邊的權值之和最小。在Floyed的同時,可以順便算出最小環。
記兩點間的最短路為dis[i][j],g[i][j]為邊< i,j > 的權值。
for(int k=1;k<=n;k++) { for(int i=1;<=k-1;i++) for(int j=i+1;j<=k-1;j++) answer=min(answer,dis[i][j]+g[j][k]+g[k][i]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); }
answer即為這張圖的最小環。
一個環中最大的節點為k,與它相連的節點為i,j,這個環的最短長度為g[i][k]+g[k][j]+(i到j的路徑中,所有節點編號都小於k的最短路徑長度)。
根據floyed原理,在最外層進行k-1次循環之后dis[i][j]則代表了i到j的路徑中,所有結點編號都小於k的最短路徑。
綜上所述,該算法一定能找到圖中的最小環。
參考博文:https://blog.csdn.net/cax1165/article/details/51811902
https://blog.csdn.net/BroDrinkWater/article/details/62416723