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 M integers 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)

本题是06年百度之星半决赛的题目,图论的最小割问题。算是图论高级内容吧。

Stoer Wager算法,当中的难点是:

1 逐条边查找最大的边的权值-过程有点想Prime算法,只是实际上不是Prime算法,由于目的并非最大生成树,而是须要把一个顶点的全部边都加起来。把这些边去掉,就是这个顶点的割点值了。那么就须要遍历整个图,到了最后一个节点才干保证是找到了这个节点的全部边。

2 缩点:所谓缩点就是把最后一个节点去掉,同一时候保留其边值信息,实际就是保留这个顶点的和其它顶点相连的最小边值。

比較难理解的,一般写这个题解报告的博客,一个是要么直接抄模板了。二是要么没有讲解;三个是有了几句讲解了。结果都没理解好,甚至错误;

也是非常难说清楚的一个题目,看看我具体凝视的程序吧。

#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <algorithm>
using namespace std; const int MAX_N = 501;
int gra[MAX_N][MAX_N];//矩阵表示图 bool shrinkedVertices[MAX_N];//标志那些顶点已经被缩点了
bool vis[MAX_N];//标志当前那些节点已经訪问了
int dis[MAX_N];//记录最大距离
int lastSec, last;//记录每次最后cut边的两个顶点
int getLastCut(int leftVertices, int n)//每次计算剩下多少没缩点的顶点计算就可以
{
fill(dis, dis+n, 0);
fill(vis, vis+n, false);
int curVer = 0;//curVer代表当前选取的顶点,初始为选取0顶点
lastSec = last = 0; //循环的主要作用的把一个顶点的全部边都加起来。仅仅有在最后一次选择的时候才干确保最后一个顶点的全部边都加起来了。
for (int i = 1; i < leftVertices; i++)
{//操作的是边。边比顶点少1的,故此i从1開始,不是从0開始
for (int v = 1; v < n; v++)
{//0顶点已经最先选择了,故此v从1開始,不是从0開始
if (!vis[v] && !shrinkedVertices[v]) dis[v] += gra[v][curVer];
}//主要是把一个顶点的全部边都加起来
int maxCut = 0;
//选取当前最大的割边。未到最后一点。不能保证是真正的割边
for (int v = 1; v < n; v++)
{
if (!vis[v] && !shrinkedVertices[v] && dis[v] > maxCut)
{
maxCut = dis[v];
curVer = v;
}
}
if (!maxCut) return 0;//本来就是分隔图,割边能够为零了。 vis[curVer] = true;
lastSec = last; last = curVer;//逐次保存最后两个顶点
}
return dis[last];
} int Stoer_Wagner(int n)
{
fill(shrinkedVertices, shrinkedVertices+n, false);
int minCut = INT_MAX;
for (int i = n; i > 1; i--)
{
minCut = min(minCut, getLastCut(i, n));
if (!minCut) return 0;
shrinkedVertices[last] = true;
for (int v = 0; v < n; v++)
{
if (!shrinkedVertices[v])
gra[lastSec][v] = gra[v][lastSec] +=
min(gra[v][last], gra[last][lastSec]);//事实上缩点就是保留当中一段边,须要保留最小值边,确保是最小割。
}
}
return minCut == INT_MAX? 0 : minCut;
} int main()
{
int N, M, u, v, w;
while (~scanf("%d %d", &N, &M))
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
gra[i][j] = 0;
}
}
for (int i = 0; i < M; i++)
{
scanf("%d %d %d", &u, &v, &w);
gra[u][v] = gra[v][u] += w;
}
printf("%d\n", Stoer_Wagner(N));
}
return 0;
}

只是上面程序的效率不高。那么能够优化一下。优化的主要方法是,利用一个数组保存好剩下的顶点,那么缩点的时候直接删除这个顶点。就不用下一次还须要遍历推断这个顶点。

这样优化了常数项,实际执行时间快了2到3倍左右,效果非常好。

#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <algorithm>
using namespace std; const int MAX_N = 501;
int gra[MAX_N][MAX_N];
int vps[MAX_N];
bool vis[MAX_N];
int dis[MAX_N];
int last, sec; int getLastCut(int V)
{
fill(vis, vis+V, false);
fill(dis, dis+V, 0);
last = sec = 0;
int id = 0;
for (int i = 1; i < V; i++)
{
int v = vps[id];
for (int j = 1; j < V; j++)
{
if (!vis[j]) dis[j] += gra[v][vps[j]];
}
int m = 0;
for (int j = 1; j < V; j++)
{
if (!vis[j] && m < dis[j]) m = dis[j], id = j;
}
if (!m) return 0;
vis[id] = true;
sec = last; last = vps[id];
}
swap(vps[id], vps[V-1]);
return dis[id];
} int Stoer_wagner(int n)
{
for (int i = 0; i < n; i++) vps[i] = i;
int minCut = INT_MAX;
for (int V = n; V > 1; V--)
{
minCut = min(minCut, getLastCut(V));
if (!minCut) return 0;
for (int i = 0; i < V; i++)
{
int v = vps[i];
gra[v][sec] = gra[sec][v] += min(gra[v][last], gra[last][sec]);
}
}
return minCut == INT_MAX? 0 : minCut;
} int main()
{
int Ver, Edge, u, v, w;
while (~scanf("%d %d", &Ver, &Edge))
{
for (int i = 0; i < Ver; i++)
for (int j = 0; j < Ver; j++)
gra[i][j] = 0; for (int i = 0; i < Edge; i++)
{
scanf("%d %d %d", &u, &v, &w);
gra[u][v] = gra[v][u] += w;
}
printf("%d\n", Stoer_wagner(Ver));
}
return 0;
}

版权声明:笔者靖心脏,景空间地址:http://blog.csdn.net/kenden23/。只有经过作者同意转载。

POJ 2914 Minimum Cut 最小割图论的更多相关文章

  1. POJ 2914 Minimum Cut 最小割算法题解

    最标准的最小割算法应用题目. 核心思想就是缩边:先缩小最大的边.然后缩小次大的边.依此缩小 基础算法:Prime最小生成树算法 只是本题測试的数据好像怪怪的,相同的算法时间执行会区别非常大,并且一样的 ...

  2. POJ2914 Minimum Cut —— 最小割

    题目链接:http://poj.org/problem?id=2914 Minimum Cut Time Limit: 10000MS   Memory Limit: 65536K Total Sub ...

  3. POJ 2914 Minimum Cut (全局最小割)

    [题目链接] http://poj.org/problem?id=2914 [题目大意] 求出一个最小边割集,使得图不连通 [题解] 利用stoerwagner算法直接求出全局最小割,即答案. [代码 ...

  4. POJ 2914 Minimum Cut Stoer Wagner 算法 无向图最小割

    POJ 2914 题意:给定一个无向图 小于500节点,和边的权值,求最小的代价将图拆为两个联通分量. Stoer Wagner算法: (1)用类似prim算法的方法求"最大生成树" ...

  5. POJ 2914 Minimum Cut【最小割 Stoer-Wangner】

    题意:求全局最小割 不能用网络流求最小割,枚举举汇点要O(n),最短增广路最大流算法求最大流是O(n2m)复杂度,在复杂网络中O(m)=O(n2),算法总复杂度就是O(n5):就算你用其他求最大流的算 ...

  6. POJ 2914 Minimum Cut 全局最小割

    裸的全局最小割了吧 有重边,用邻接矩阵的时候要小心 #include<iostream> #include<cstdio> #include<bitset> #in ...

  7. POJ 2914 - Minimum Cut - [stoer-wagner算法讲解/模板]

    首先是当年stoer和wagner两位大佬发表的关于这个算法的论文:A Simple Min-Cut Algorithm 直接上算法部分: 分割线 begin 在这整篇论文中,我们假设一个普通无向图G ...

  8. POJ 2914 Minimum Cut

    Minimum Cut Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 9319   Accepted: 3910 Case ...

  9. HDU 6214 Smallest Minimum Cut 最小割,权值编码

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6214 题意:求边数最小的割. 解法: 建边的时候每条边权 w = w * (E + 1) + 1; 这 ...

随机推荐

  1. Python3.2官方文档翻译--实例对象和方法对象

    6.3.3 实例对象 如今我们用实例对象做什么呢?实例对象唯一可用的操作就是属性引用.如今有两种合法的属性名称:数据属性和方法. 数据属性相当于smallTalk中的实例变量,C++中的数据成员.数据 ...

  2. [IDEs]Eclipse自动格式化代码

    格式化代码快捷键:Ctrl + Shift + F 一般情况: 1).Ctrl + A 2).Ctrl + Shift + F ps: 格式化之后发现代码换行了,因为已经达到最大长度,可修改设置,增加 ...

  3. 当Scheduler拿不到url的 时候,不能立即退出

    在webmagic的多线程抓取中有一个比较麻烦的问题:当Scheduler拿不到url的 时候,不能立即退出,需要等到没抓完的线程都运行完毕,没有新url产生时,才能退出.之前使用Thread.sle ...

  4. 从零開始制作H5应用(4)——V4.0,增加文字并给文字加特效

    之前,我们分三次完毕了我们第一个H5应用的三个迭代版本号: V1.0--简单页面滑动切换 V2.0--多页切换,透明过渡及交互指示 V3.0--加入loading,music及自己主动切换 这已经是一 ...

  5. 灰度共生矩阵(GLCM) 及matlab代码实现

    原地址:http://blog.csdn.net/bookwormno1/article/details/7962466 这几天学习灰度共生矩阵,现记录如下: 讲灰度共生矩阵比较好的一份百度文库文档: ...

  6. vim php代码规范

    vim 代码规范工具php-cs-fixer.phar (參考https://github.com/FriendsOfPHP/PHP-CS-Fixer) INSTALL curl http://get ...

  7. JavaScript RegExp对象

    一.什么是RegExp         1.RegExp 是正則表達式的缩写. 2.当您检索某个文本时,能够使用一种模式来描写叙述要检索的内容.RegExp 就是这样的模式. 3.简单的模式能够是一个 ...

  8. mysql联合索引的应用

    有一个log表,结构是这样的: CREATE TABLE `weblog` (   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,   `ip` varc ...

  9. 【解决方法】ADT在线安装

    作为android开发者,不知道被ADT更新.SDK更新这些更新给强奸了多少次. 今天……我又一次被凌辱了. 无论是 https://dl-ssl.google.com/android/eclipse ...

  10. oracle的to_char中的fm

    SQL> select '|'||to_char(5,'999')||'|' from dual;  结果为:|   5| SQL> select '|'||to_char(5,'000' ...