• bzoj4883 [Lydsy1705月赛]棋盘上的守卫 最小生成基环树森林


    题目传送门

    https://lydsy.com/JudgeOnline/problem.php?id=4883

    题解

    每一行和每一列都必须要被覆盖。

    考虑对于每一行和每一列都建立一个点,一行和一列之间的连边就是对应坐标的点权。

    这样,每一个点都必须要有一个出边以表示这一行/列选择了这个边。

    每个点都必须要有一个出边就是基环树森林了。

    所以直接用 kruskal 维护最小基环树森林。

    维护方法大概就是并查集的时候再维护一个信息表示这个连通块存不存在环。一条边可以贡献,第一个时候是在两个连通块不连通并且两个连通块不都有环;第二个时候是两个端点在一个连通块中,并且这个连通块没有环。


    时间复杂度 \(O(nm\log nm)\)

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 100000 + 7;
    
    int n, m, tot;
    int fa[N], hs[N];
    
    struct Edges { int x, y, w; } e[N];
    inline bool operator < (const Edges &a, const Edges &b) { return a.w < b.w; }
    
    inline int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
    
    inline void work() {
    	std::sort(e + 1, e + n * m + 1);
    	ll ans = 0;
    	for (int i = 1; i <= n + m; ++i) fa[i] = i;
    	for (int i = 1; i <= n * m; ++i) {
    		int x = find(e[i].x), y = find(e[i].y), z = e[i].w;
    //		dbg("z = %d\n", z);
    		if (x == y) {
    			if (!hs[x]) hs[x] = 1, ans += z;//, dbg("****** %d %d %d\n", e[i].x, e[i].y, z);
    			continue;
    		}
    		if (hs[x] && hs[y]) continue;
    		ans += z, fa[y] = x, hs[x] |= hs[y];//, dbg("****** %d %d %d\n", e[i].x, e[i].y, z);
    	}
    	printf("%lld\n", ans);
    }
    
    inline void init() {
    	read(n), read(m);
    	int v;
    	for (int i = 1; i <= n; ++i)
    		for (int j = 1; j <= m; ++j) {
    			read(v);
    			e[++tot] = (Edges){ i, j + n, v };
    		}
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    关闭编辑easyui datagrid table
    sql 保留两位小数+四舍五入
    easyui DataGrid 工具类之 util js
    easyui DataGrid 工具类之 后台生成列
    easyui DataGrid 工具类之 WorkbookUtil class
    easyui DataGrid 工具类之 TableUtil class
    easyui DataGrid 工具类之 Utils class
    easyui DataGrid 工具类之 列属性class
    oracle 卸载
    “云时代架构”经典文章阅读感想七
  • 原文地址:https://www.cnblogs.com/hankeke303/p/bzoj4883.html
Copyright © 2020-2023  润新知