1. 程式人生 > 實用技巧 >微信公眾號開啟伺服器配置 JAVA

微信公眾號開啟伺服器配置 JAVA

應用

  • 求多源點最短路
  • 傳遞閉包
  • 找最小環(對於正權圖而言)
  • 恰好經過k條邊的最短路

floyd演算法原理

演算法模板

//初始化:d[i][i] = 0 且不相連的節點距離需要初始化為INF
for(int k = 0; k < n; k++)
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            d[i][j] = min(d[i][j] , d[i][k] + d[k][j]);

空間優化

  • 需要說明表示式d[k][i][j] = min(d[k][i][j] , d[k-1][i][k] + d[k-1][k][j])
    d[i][j] = min(d[i][j] , d[i][k] + d[k][j])等價
  • d[k-1][i][k] <=> d[i][k]為例,只需要說明每一次d[i][k]的值可能被更新時,d[i][k]的值不變
  • j=k, 則d[k][i][k] = min(d[k][i][k] , d[k-1][i][k] + d[k-1][k][k]).因為d[k-1][k][k]=0,所以d[i][k]的值不會發生改變,總是第k-1層的值

例題-牛的旅行

題目連結

題解

1.根據輸入建立鄰接矩陣d,跑一邊floyd演算法
2.求每一個連通塊的直徑(距離最遠的兩點的距離),答案必定>=每一連通塊的直徑
3.列舉連線兩個連通塊內的某點所形成的新連通塊的直徑中的最小值,答案必定>=這個最小值
4.新的連通塊直徑(例如連線i,j兩點):maxd[i] + dist(i , j) + maxd[j]

程式碼

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 160;
const double INF = 1e20;
#define x first
#define y second
typedef pair<int ,int> PII;
PII p[N];
double d[N][N] , maxd[N];
char g[N][N];
int n;

double get_dist(PII a , PII b)
{
    double x = a.x - b.x , y = a.y - b.y;
    return sqrt(x*x + y*y);
}

int main()
{
    cin >> n;
    for(int i = 0; i < n; i++)  cin >> p[i].x >> p[i].y;

    for(int i = 0; i < n; i++)  cin >> g[i];

    //初始化距離
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            if(i != j)
            {
                if(g[i][j] == '1') d[i][j] = get_dist(p[i] , p[j]);
                else d[i][j] = INF;
            }

    //Floyd演算法
    for(int k = 0; k < n; k++)
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                d[i][j] = min(d[i][j] , d[i][k] + d[k][j]);

    //求連通塊內的直徑
    for(int i = 0; i < n; i++)
        for(int j = 0;j < n; j++)
            if(d[i][j] < INF)
                maxd[i] = max(maxd[i] , d[i][j]);

    //情況1:結果必然 >= 每一連通塊的直徑
    double ans = 0;
    for(int i = 0; i < n; i++)  ans = max(ans , maxd[i]);

    //情況2:結果必然 >= 連線一條邊後新的連通塊的直徑(列舉最小值)
    double res = INF;
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            if(d[i][j] >= INF)
                res = min(res , maxd[i] + get_dist(p[i] , p[j]) + maxd[j]);

    printf("%lf\n" , max(ans , res));

    return 0;
}

例題-排序(傳遞閉包)

floyd演算法求傳遞閉包

  • 1.鄰接矩陣初始化d[i][j]:1-表示i,j之間存在i到j的單向路徑 0-表示不存在路徑
  • 2.將轉移關係修改為:d[i][j] = d[i][j] | ( d[i][k] & d[k][j] ) -(表示 i->k , k->j兩段路徑都存在)
  • 3.整體認識:在演算法結束後,所有的間接關係,例如 i->j , j->k,會直接表示出來,即d[i][k] = 1

題解

  • 在本題中可以將A < B類比成A->B
  • 則存在矛盾例如A<B , B<C , C<A , 可以推知A<A , 即A->A , d[i][i] = 1
  • 變數A,B不存在相對關係:d[a][b] = 0 && d[b][a] = 0

程式碼

#include <iostream>
#include <cstring>
using namespace std;
const int N = 30;
int d[N][N] , g[N][N];
int n , m;

void floyd()
{
    memcpy(d , g , sizeof g);

    for(int k = 0; k < n; k++)
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j ++)
                d[i][j] |= d[i][k] & d[k][j];
}

int check()
{
    for(int i = 0; i < n; i++)
        if(d[i][i]) return 2;

    for(int i = 0; i < n; i++)
        for(int j = i + 1; j < n; j++)
            if(!d[i][j] && !d[j][i])  return 0;

    return 1;
}

char get_min(int val)
{
    for(int i = 0; i < n; i++)
    {
        int cnt = 0;
        for(int j = 0; j < n; j++)
            if(d[i][j]) cnt++;
        if(cnt == val) return i + 'A';
    }
}

int main()
{
    while(cin >> n >> m , n || m)
    {
        char str[4];
        //type: 0-表示存在無法判斷的關係  1-表示所有關係已確定   2-關係存在矛盾
        int type = 0 , t;

        memset(g , 0 , sizeof g);
        for(int i = 1; i <= m; i++)
        {
            cin >> str;
            int a = str[0] - 'A' , b = str[2] - 'A';

            if(!type)
            {
                g[a][b] = 1;
                floyd();
                type = check();
                if(type) t = i;
            }
        }    
            if(!type) printf("Sorted sequence cannot be determined.\n");
            else if(type == 2)  printf("Inconsistency found after %d relations.\n" , t);
            else
            {
                printf("Sorted sequence determined after %d relations: " , t);
                for(int i = 0; i < n; i++)
                    printf("%c" , get_min(n - i - 1));
                puts(".");
            }
    }

    return 0;
}

參考文獻

Acwing-演算法提高課-圖論章節
https://www.acwing.com/activity/content/introduction/16/