HDU 3035 War(对偶图求最小割)

HDU 3035 War

题目链接

题意:根据图那样,给定一个网络,要求阻断s到t,需要炸边的最小代价

思路:显然的最小割,但是也显然的直接建图强行网络流会超时,这题要利用平面图求最小割的方法,把每一块当成一个点,共有边连边,然后每一个路径就是一个割,然后最短路就是最小割了

代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;

const int MAXNODE = 1000005;
const int MAXEDGE = 3 * MAXNODE;

typedef int Type;
const Type INF = 0x3f3f3f3f;

struct Edge {
	int u, v;
	Type dist;
	Edge() {}
	Edge(int u, int v, Type dist) {
		this->u = u;
		this->v = v;
		this->dist = dist;
	}
};

struct HeapNode {
	Type d;
	int u;
	HeapNode() {}
	HeapNode(Type d, int u) {
		this->d = d;
		this->u = u;
	}
	bool operator < (const HeapNode& c) const {
		return d > c.d;
	}
};

struct Dijkstra {
	int n, m;
	Edge edges[MAXEDGE];
	int first[MAXNODE];
	int next[MAXEDGE];
	bool done[MAXNODE];
	Type d[MAXNODE];

	void init(int n) {
		this->n = n;
		memset(first, -1, sizeof(first));
		m = 0;
	}

	void add_Edge(int u, int v, Type dist) {
		edges[m] = Edge(u, v, dist);
		next[m] = first[u];
		first[u] = m++;
	}

	Type dijkstra(int s, int t) {
		priority_queue<HeapNode> Q;
		for (int i = 0; i < n; i++) d[i] = INF;
		d[s] = 0;
		memset(done, false, sizeof(done));
		Q.push(HeapNode(0, s));
		while (!Q.empty()) {
			HeapNode x = Q.top(); Q.pop();
			int u = x.u;
			if (done[u]) continue;
			done[u] = true;
			for (int i = first[u]; i != -1; i = next[i]) {
				Edge& e = edges[i];
				if (d[e.v] > d[u] + e.dist) {
					d[e.v] = d[u] + e.dist;
					Q.push(HeapNode(d[e.v], e.v));
				}
			}
		}
		return d[t];
	}
} gao;

typedef long long ll;

int n, m;

int main() {
	while (~scanf("%d%d", &n, &m)) {
		int u, v, w;
		gao.init(n * m * 4 + 2);
		int s = n * m * 4, t = n * m * 4 + 1;
		for (int i = 0; i < (n + 1); i++) {
			for (int j = 0; j < m; j++) {
				scanf("%d", &w);
				u = (i - 1) * m + j + n * m;
				v = i * m + j;
				if (i == 0) u = t;
				if (i == n) v = s;
				gao.add_Edge(u, v, w);
				gao.add_Edge(v, u, w);
			}
		}
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < (m + 1); j++) {
				scanf("%d", &w);
				u = n * m * 3 + i * m + j - 1;
				v = n * m * 2 + i * m + j;
				if (j == 0) u = s;
				if (j == m) v = t;
				gao.add_Edge(u, v, w);
				gao.add_Edge(v, u, w);
			}
		}
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				scanf("%d", &w);
				u = i * m + j;
				v = n * m * 2 + i * m + j;
				gao.add_Edge(u, v, w);
				gao.add_Edge(v, u, w);
				scanf("%d", &w);
				v += n * m;
				gao.add_Edge(u, v, w);
				gao.add_Edge(v, u, w);
			}
			for (int j = 0; j < m; j++) {
				scanf("%d", &w);
				u = n * m + i * m + j;
				v = n * m * 2 + i * m + j;
				gao.add_Edge(u, v, w);
				gao.add_Edge(v, u, w);
				scanf("%d", &w);
				v += n * m;
				gao.add_Edge(u, v, w);
				gao.add_Edge(v, u, w);
			}
		}
		printf("%d\n", gao.dijkstra(s, t));
	}
	return 0;
}
时间: 2024-10-27 13:09:41

HDU 3035 War(对偶图求最小割)的相关文章

HDU - 3035 War(对偶图求最小割+最短路)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3035 题意 给个图,求把s和t分开的最小割. 分析 实际顶点和边非常多,不能用最大流来求解.这道题要用平面图求最小割的方法: 把面变成顶点,对每两个面相邻的边作一条新边.然后求最短路就是最小割了. 另外,外平面分成两个点,分别是源点和汇点,源点连左下的边,汇点连右上的边,这样跑出来才是正确的. 建图参考自:https://blog.csdn.net/accelerator_/article/deta

HDU 2435 There is a war (网络流-最小割)

There is a war Problem Description There is a sea. There are N islands in the sea. There are some directional bridges connecting these islands. There is a country called Country One located in Island 1. There is another country called Country Another

BZOJ_1001_狼抓兔子(平面图求最小割+对偶图求最短路)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1001 分析 平面图求最小割,转化成对偶图求最短路,经典. 注意: 1.优先队列是个大根堆. 2.Dijkstra可以带一个vis数组,也可以不带,因为一个点出来以后,它更新的的点和原本就在队列里的点都比它大,所以它不可能被更新得更小,之后这个点再出队时情况不比第一次更优,所以出队也不会有操作. 3.双向边,数组要开够(貌似不是第一次犯这个错误). 4.网上有人说m==1||n==1的情况可以

HDU 1565 (最大流+黑白染色化二分图求最小割)

http://acm.hdu.edu.cn/showproblem.php?pid=1565 思路:将横纵坐标和为偶尔染白色,其他染黑色,黑点连接源点,流量为该点的值,白点连接汇点,流量为该点的值,黑白点有相邻的就连边,值为无穷大.最后求最大流,即该图的最小割. PS:刚开始不明白为为什么最大流会等于最小割,为什么所有的点之和减去最小割就会等于答案. 我的理解是:整张图其实就跟连接管道一样,连接了黑点表示取了黑点那个值的流量,白点也是,而连接了相邻的黑白点求出的最大流就会是流量较小的那个的值.好

hdu 3987 求最小割条数最小

题意:    一个人要从起点  0  到达 n-1   n个点  m条路  ,我们求最少破坏路的条数使无法 从起点到达终点.题意很明显  ,求最小割条数最少,由于最小割流量虽然固定,但是其条数却不固定,可以破坏3条路,也可以破坏4条路,他们总流量相同才会出现这种情况. 题解:由于上述的情况,他们总流量相同但是条数不同,现在我们需要改变边的容量使得条数少边才是最小割,条数多的将不会是最小割. 官方题解有两种 ,我选择的是在残余网络中进行扩充流的操作,使的两个最小割不同,残余网络中,我进行所有边流量

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6214 题意:求边数最小的割. 解法: 建边的时候每条边权 w = w * (E + 1) + 1; 这样得到最大流 maxflow / (E + 1) ,最少割边数 maxflow % (E + 1) 道理很简单,如果原先两类割边都是最小割,那么求出的最大流相等 但边权变换后只有边数小的才是最小割了 乘(E+1)是为了保证边数叠加后依然是余数,不至于影响求最小割的结果 因为假设最小割=k,那么现在新

HDU 4289:Control(最小割)

http://acm.hdu.edu.cn/showproblem.php?pid=4289 题意:有n个城市,m条无向边,小偷要从s点开始逃到d点,在每个城市安放监控的花费是sa[i],问最小花费可以监控到所有小偷. 思路:求最小割可以转化为最大流.每个城市之间拆点,流量是sa[i],再增加一个超级源点S和s相连,增加一个超级汇点T,让d的第二个点和T相连.然后就可以做了. 1 #include <cstdio> 2 #include <algorithm> 3 #include

HDU 4289 Control (网络流-最小割)

Control Problem Description You, the head of Department of Security, recently received a top-secret information that a group of terrorists is planning to transport some WMD 1 from one city (the source) to another one (the destination). You know their

HDU 3657 Game(取数 最小割)经典

Game Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1065    Accepted Submission(s): 449 Problem Description onmylove has invented a game on n × m grids. There is one positive integer on each g