POJ 2914-Minimum Cut(Stoer_Wagner最小割演算法)

kewlgrl發表於2016-07-26
Minimum Cut
Time Limit: 10000MS   Memory Limit: 65536K
Total Submissions: 8853   Accepted: 3746
Case Time Limit: 5000MS

Description

Given an undirected graph, in which two vertices can be connected by multiple edges, what is the size of the minimum cut of the graph? i.e. how many edges must be removed at least to disconnect the graph into two subgraphs?

Input

Input contains multiple test cases. Each test case starts with two integers N and M (2 ≤ N ≤ 500, 0 ≤ M ≤ N × (N − 1) ⁄ 2) in one line, where N is the number of vertices. Following are M lines, each line contains Mintegers AB and C (0 ≤ AB < NA ≠ BC > 0), meaning that there C edges connecting vertices A and B.

Output

There is only one line for each test case, which contains the size of the minimum cut of the graph. If the graph is disconnected, print 0.

Sample Input

3 3
0 1 1
1 2 1
2 0 1
4 3
0 1 1
1 2 1
2 3 1
8 14
0 1 1
0 2 1
0 3 1
1 2 1
1 3 1
2 3 1
4 5 1
4 6 1
4 7 1
5 6 1
5 7 1
6 7 1
4 0 1
7 3 1

Sample Output

2
1
2

Source

Baidu Star 2006 Semifinal 
Wang, Ying (Originator) 

Chen, Shixi (Test cases)

題目意思:

N個點,M行,每行給出A點到B點之間有C條路徑,求最小割。

解題思路:

求最小割的裸題,必會stoer_wagner最小割演算法

演算法實現思路:

1. 設最小割cut=INF, 任選一個點s到集合A中, 定義W(A, p)為A中的所有點到A外一點p的權總和.

2. 對剛才選定的s, 更新W(A,p)(該值遞增).

3. 選出A外一點p, 且W(A,p)最大的作為新的s, 若A!=G(V), 則繼續2.

4. 把最後進入A的兩點記為s和t, 用W(A,t)更新cut.

5. 新建頂點u, 邊權w(u, v)=w(s, v)+w(t, v), 刪除頂點s和t, 以及與它們相連的邊.

6. 若|V|!=1則繼續1.

相同的或者是:

1.min=MAXINT,固定一個頂點P

2.從點P用“類似”prim的s演算法擴充套件出“最大生成樹”,記錄最後擴充套件的頂點和最後擴充套件的邊

3.計算最後擴充套件到的頂點的切割值(即與此頂點相連的所有邊權和),若比min小更新min

4.合併最後擴充套件的那條邊的兩個端點為一個頂點(當然他們的邊也要合併,這個好理解吧?)

5.轉到2,合併N-1次後結束

6.min即為所求,輸出min

prim本身複雜度是O(n^2),合併n-1次,演算法複雜度即為O(n^3)


傳送門:

程式碼From

演算法分析

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define MAX_N 505
#define INF 0x3f3f3f3f

int G[MAX_N][MAX_N];//原圖
int v[MAX_N];//v[i]代表節點i合併到的頂點
int w[MAX_N];//定義w(A,x) = ∑w(v[i],x),v[i]∈A
bool visited[MAX_N];//用來標記是否該點加入了A集合
int s,t;//源點與匯點
int stoer_wagner(int n)//stoer_wagner最小割演算法
{
    int min_cut = INF;//最小割cut=INF
    int i, j, k;
    for (i = 0; i < n; ++i)
        v[i] = i;//初始還未合併所以都代表節點本身
    while (n > 1)
    {
        int pre = 0;//pre用來表示之前加入A集合的點(在t之前一個加進去的點)
        memset(visited, 0, sizeof(visited));
        memset(w, 0, sizeof(w));
        /******************從點s開始擴充套件出一棵最大生成樹**********************/
        for (i = 1; i < n; ++i)//任選一個點s到集合A中, 定義W(A, p)為A中的所有點到A外一點p的權總和
        {
            k = -1;
            for (j = 1; j < n; ++j)//選取V-A中的w(A,x)最大的點x加入集合
                if (!visited[v[j]])//該點還沒有加入A集合
                {
                    w[v[j]] += G[v[pre]][v[j]];//對剛才選定的s, 更新W(A,p)(該值遞增)
                    if (k == -1 || w[v[k]] < w[v[j]])//選出A外一點p, 且W(A,p)最大的作為新的s
                        k = j;
                }
            visited[v[k]] = true;//標記該點x已經加入A集合
            /****************************************/
            if(i == n-1)//若|A|=|V|(所有點都加入了A),結束
            {
                min_cut = min(min_cut, w[t]);//把最後進入A的兩點記為s和t,則s-t最小割為w(A,t),用其更新min_cut
                for (j = 0; j < n; ++j)	//Contract(s, t), 合併st,即新建頂點u, 邊權w(u, v)=w(s, v)+w(t, v), 刪除頂點s和t, 以及與它們相連的邊
                {
                    G[s][v[j]] += G[v[j]][t];
                    G[v[j]][s] += G[v[j]][t];
                }
                v[k] = v[--n];//刪除最後一個點(即刪除t,也即將t合併到s),若|V|!=1則繼續
                s = v[pre], t = v[k];//令倒數第二個加入A的點(v[pre])為s,最後一個加入A的點(v[k])為t
            }
            pre = k;//繼續
        }
    }
    return min_cut;
}

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n, m;
    while (cin>>n>>m)
    {
        memset(G, 0, sizeof(G));
        while (m--)
        {
            int u, v, w;
            cin>>u>>v>>w;
            G[u][v] += w;
            G[v][u] += w;
        }
        cout<<stoer_wagner(n)<<endl;
    }
    #ifndef ONLINE_JUDGE
        fclose(stdin);
        fclose(stdout);
        system("out.txt");
    #endif
    return 0;
}


相關文章