POJ 2914 Minimum Cut 最小割图论

POJ 2914 Minimum Cut 最小割图论

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/116766.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • WordPress使用淘宝IP地址库的API显示评论者的位置信息(二)

    WordPress使用淘宝IP地址库的API显示评论者的位置信息(二)

    2021年11月5日
    55
  • currentstyle 织梦_设置typeid后织梦currentstyle 不起作用的修复方法

    {dede:channeltype=’son’row=’8’currentstyle=”~typename~”}[field:typename/]{/dede:channel}这种调用方式currentstyle有效但是设置typeid:{dede:channeltype=’son’row=’8’typeid=1currentstyle=”~typename~”}[…

    2022年4月9日
    41
  • 2022Android SDK下载与安装

    2022Android SDK下载与安装一、下载sdk:https://www.androiddevtools.cn找个合适的位置解压双击“SDKManager.exe”,启动SDKManager安装工具我们可以通过有AndroidSDK的国内镜像服务器来下载安装,这里推荐几个:1、中科院开源协会镜像站地址:IPV4/IPV6:http://mirrors.opencas.ac.cn端口:802、北京化工大学镜像服务器地址:IPv4:http://ubuntu.buct.edu.cn/端口:80IPv

    2022年7月19日
    18
  • (怪盗基德的滑翔翼)(最长上升子序列)[通俗易懂]

    (怪盗基德的滑翔翼)(最长上升子序列)[通俗易懂]原题链接怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。不得已,怪盗基德只能操作受损的滑翔翼逃脱。假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。初始时,怪盗基德可以在任何一幢建筑的顶端。他可以选择一个方向逃跑,但是不能中途改变方向

    2022年8月8日
    10
  • django配置文件详解_pycharm配置django

    django配置文件详解_pycharm配置django前言django框架的日志通过python内置的logging模块实现的,既可以记录自定义的一些信息描述,也可以记录系统运行中的一些对象数据,还可以记录包括堆栈跟踪、错误代码之类的详细信息。log

    2022年7月30日
    11
  • 妇产科护理学试题库及答案_妇产科护理学题库集各章节

    妇产科护理学试题库及答案_妇产科护理学题库集各章节试题一1.关于子宫的位置与形态,正确的为DA.位于盆腔下方B.形如扁梨形C.容积为2mlD.前与膀胱,后与直肠为邻E.子宫峡部非孕时长3cm2.保持子宫前倾位置的一对主要韧带是CA.圆韧带B.阔韧带C.主韧带D.骨盆漏斗韧带E.子宫骶骨韧带3.与后穹隆顶端贴接的部分为EA.宫颈口B.附件C.膀胱D.直肠E.直肠子宫陷凹4.关于骨盆外测量径线的描述,错误的是BA.髂棘间径为两侧髂前上棘外缘间的距离B.坐骨结节间径为两侧坐骨结节外缘间的距离C

    2025年7月10日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号