zoukankan      html  css  js  c++  java
  • BZOJ 4883 [Lydsy2017年5月月赛]棋盘上的守卫(最小生成环套树森林)

    【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=4883

    【题目大意】

      在一个n*m的棋盘上要放置若干个守卫。
      对于n行来说,每行必须恰好放置一个横向守卫;同理对于m列来说,
      每列必须恰好放置一个纵向守卫。每个位置放置守卫的代价是不一样的,
      且每个位置最多只能放置一个守卫,一个守卫不能同时兼顾行列的防御。
      请计算控制整个棋盘的最小代价。

    【题解】

      我们将每行和每列看成一个点,用每个格子上的点的权值作为边,
      这就构成了一个n+m个点的图。
      我们发现对于n个点的集合,为了满足题目中的要求,就至少要包含n条边。
      所以题目就转化成求图中的最小生成环套树森林。

    【代码】

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    const int N=200010;
    LL ans;
    int x,n,m,f[N],v[N];
    struct E{int u,v,c;E(){}E(int u,int v,int c):u(u),v(v),c(c){};}e[N];
    bool cmp(E x,E y){return x.c<y.c;}
    int sf(int x){return x==f[x]?x:f[x]=sf(f[x]);}
    int main(){
        while(~scanf("%d%d",&n,&m)){
            int cnt=ans=0;
            for(int i=1;i<=n+m;i++)f[i]=i,v[i]=0;
            for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
                scanf("%d",&x);
                e[++cnt]=E(i,j+n,x);
            }sort(e+1,e+cnt+1,cmp);
            for(int i=1;i<=cnt;i++){
                int fx=sf(f[e[i].u]),fy=sf(f[e[i].v]);
                if(v[fx]&&v[fy])continue;
                if(fx!=fy)v[fy]|=v[fx],f[fx]=fy;else v[fx]=1;
                ans+=e[i].c;
            }printf("%lld
    ",ans);
        }return 0;
    }
  • 相关阅读:
    InnoDB实现MVCC原理
    Python中定义函数时参数有默认值的小陷阱
    Python系统编程笔记
    Python中的字典
    Python中常见的字符串小笔试题
    Oracle常见名词解析
    Oracle数据库面试题【转载】
    Oracle日期语言修改
    Oracle日期时间函数大全
    Oracle数据库分页的三种方法
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj4883.html
Copyright © 2011-2022 走看看