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/。只有经过作者同意转载。

最新文章

  1. linux命令crontab
  2. Java多线程编程核心技术---拾遗增补
  3. cocopods 知识集合 及 一个 好的 国外iOS技术翻译站
  4. iOS删除本地文件
  5. 解决IE6不支持position:fixed;的问题
  6. android performClick使用
  7. Python你必须知道的十个库
  8. Nubia Z5S 基于官方H207/4.4内核的Mokee4.4.4 RC3.2 (2014.7.31修复呼吸灯(能亮依旧不能呼吸))
  9. hdu1372 dfs搜索之国际象棋的马
  10. winform自动更新并实现文件的批量异步下载
  11. 64位Java开发平台的选择,如何区分JDK,Tomcat,eclipse的32位与64版本
  12. webpack 相关资料
  13. C++ STL Binary search详解
  14. 关于session共享的解决方法
  15. Django 基础一(安装和启动)
  16. Subsequence(序列自动机模板题)
  17. 用JDBC连接 数据库 进行简单的增删改查
  18. JS----对象的合并与克隆
  19. 转 tomcat+nginx+redis实现均衡负载、session共享(二)
  20. Python:Day53 Template基础

热门文章

  1. C# split字符串 依据1个或多个空格
  2. DataReader和DataSet的区别以及使用
  3. [翻译]利用C#获取终端服务(Terminal Services)会话的闲置时间
  4. 一个Java对象到底占多大内存?(转)
  5. 图片本地预览 flash html5
  6. VSTO 向office文档中插入内容
  7. 欧舒丹 L'Occitane 活力清泉保湿面霜 - 男士护肤 - 香港草莓网StrawberryNET.com
  8. DIV固定在页面某个位置,不随鼠标滚动而滚动
  9. Ctrl-A全选
  10. hdu2606(递推)