• BZOJ-1001 [BeiJing2006]狼抓兔子


    解题思路:

    这道题目是关于最小割的一道题目。

    最小割的经典算法是根据最大流最小割定理,将最小割化成最大流然后用dinic算法求解

    不过这题比较特殊,即使转换成最大流求最小割依旧不可能通过。因为时间和空间的双重限制,所以这道题的解法需要利用这个图的特殊性质。

    给出的图是一个平面图无疑,那么利用平面图的特殊性质解决这个问题会简单很多。

    将平面图转换成其对偶图,然后计算新的源点到新的汇点的最短路径即可得出结果。

    然后关于这个题目,有一篇资料写的很好推荐一发:传送门

    听说这题用dijkstra+heap速度更快。

    代码:

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    typedef struct node {
    	int v, cap, nxt;
    	node(int a = 0, int b = 0, int c = 0) {
    		v = a; cap = b; nxt = c;
    	}
    }Edge;
    
    const int maxn = 2100005;
    const int maxm = 6100005;
    const int inf = 0x3f3f3f3f;
    
    Edge edge[maxm];
    int tot, head[maxn];
    int vis[maxn], dis[maxn];
    
    void add(int u, int v, int cap) {
    	edge[tot] = Edge(v, cap, head[u]);
    	head[u] = tot++;
    	edge[tot] = Edge(u, cap, head[v]);
    	head[v] = tot++;
    }
    int spfa(int s, int t) {
    	int x;
    	Edge e;
    	queue<int> q;
    	while (!q.empty()) q.pop();
    	memset(vis, 0, sizeof(vis));
    	memset(dis, 0x3f, sizeof(dis));
    	
    	dis[s] = 0; vis[s] = 1; q.push(s);
    	while (!q.empty()) {
    		x = q.front(); q.pop(); vis[x] = 0;
    		for (int i = head[x]; ~i; i = edge[i].nxt) {
    			e = edge[i];
    			if (dis[x] + e.cap < dis[e.v]) {
    				dis[e.v] = dis[x] + e.cap;
    				if (!vis[e.v]) {
    					vis[e.v] = 1;
    					q.push(e.v);
    				}
    			}
    		}
    	}
    	return dis[t];
    }
    int main() {
    	int n, m, u, v, cap;
    	while (~scanf("%d%d", &n, &m)) {
    		if (n == 1 || m == 1) {
    			if (n > m) swap(n, m);
    			int ans = inf;
    			for (int i = 1, a; i < m; ++i) {
    				scanf("%d", &a);
    				ans = min(ans, a);
    			}
    			printf("%d
    ", ans == inf ? 0 : ans);
    			continue;
    		}
    		int s = 0, t = (m - 1) * 2 * (n - 1) + 1;
    		tot = 0;
    		memset(head, -1, sizeof(head));
    		for (int i = 1; i <= n; ++i) {
    			for (int j = 1; j <= m - 1; ++j) {
    				scanf("%d", &cap);
    				if (i == 1) { u = s; v = 2 * j; }
    				else if (i == n) { u = (m - 1) * (n - 2) * 2 + 2 * j - 1; v = t; }
    				else { v = (m - 1) * 2 * (i - 2) + 2 * j - 1; u = (m - 1) * 2 * (i - 1) + 2 * j; }
    				add(u, v, cap);
    				//printf("u = %d, v = %d, cap = %d
    ", u, v, cap);
    			}
    		}
    		for (int i = 1; i < n; ++i) {
    			for (int j = 1; j <= m; ++j) {
    				scanf("%d", &cap);
    				if (j == 1) { v = t; u = (m - 1)*(i - 1) * 2 + 1; }
    				else if (j == m) { u = s; v = (m - 1) * i * 2; }
    				else { u = (m - 1) * (i - 1) * 2 + 2 * (j - 1); v = u + 1; }
    				add(u, v, cap);
    				//printf("u = %d, v = %d, cap = %d
    ", u, v, cap);
    			}
    		}
    		for (int i = 1; i < n; ++i) {
    			for (int j = 1; j < m; ++j) {
    				scanf("%d", &cap);
    				u = (m - 1) * 2 * (i - 1) + 2 * j - 1; 
    				v = u + 1;
    				add(u, v, cap);
    				//printf("u = %d, v = %d, cap = %d
    ", u, v, cap);
    			}
    		}
    		printf("%d
    ", spfa(s, t));
    	}
    	return 0;
    }


  • 相关阅读:
    Win10家庭版无法远程桌面连接的解决方法
    分分钟用上C#中的委托和事件之窗体篇
    分分钟用上C#中的委托和事件
    Fiddler工具使用介绍三
    Fiddler工具使用介绍二
    Fiddler工具使用介绍一
    Hexo主题开发
    IDEA 编译 Jmeter 4.0 ( 二次开发_1 )
    Pinpoint 安装部署
    接口测试总结
  • 原文地址:https://www.cnblogs.com/wiklvrain/p/8179363.html
Copyright © 2020-2023  润新知