圖的連通性問題之連通和最小環——Floyd算法


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個整數,表示排名可以確定的奶牛的數目

 

輸入輸出樣例

輸入樣例#1:  復制
5 5
4 3
4 2
3 2
1 2
2 5
輸出樣例#1:  復制
2

說明

輸出說明:

編號為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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM