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


    法1——图论:

    其实图论并不是我一开始就想出来的。。。纯粹是先受了网络流做法的启发改进的。对于每个士兵都要守护一行或者一列,将守护行看做标号$i$的点,连向所在的列$y+n$(注意平移),守护列则反过来。这样,这张图上每个点都有一个出边,这就是一片基环树森林。但是要注意的是,同一条边的两个方向不能同时被选择,因为同一个不能被占用多次,所以不妨做以下等价转换:直接把每对$(x,y)$连一条无向边,做最小基环树森林求解。这样因为基环树保证每个点可以有一个出度(这个可以根据题意自己定向),同时有保证了同一条边不会被选两次。所以就变成了裸的板子。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define dbg(x) cerr << #x << " = " << x <<endl
     8 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
     9 using namespace std;
    10 typedef long long ll;
    11 typedef double db;
    12 typedef pair<int,int> pii;
    13 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    14 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    15 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    16 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    17 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    18 template<typename T>inline T read(T&x){
    19     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    20     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    21 }
    22 const int N=1e5+7;
    23 struct thxorz{
    24     int u,v,w;
    25     inline bool operator <(const thxorz&A)const{return w<A.w;}
    26 }e[N];
    27 int anc[N],cir[N];
    28 inline int find_anc(int x){return anc[x]==x?x:anc[x]=find_anc(anc[x]);}
    29 int n,m,tot;
    30 ll ans;
    31 
    32 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    33     read(n),read(m);
    34     for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)e[++tot].u=i,e[tot].v=j+n,read(e[tot].w);
    35     for(register int i=1;i<=n+m;++i)anc[i]=i;
    36     sort(e+1,e+tot+1);
    37     for(register int i=1;i<=tot;++i){
    38         int fx=find_anc(e[i].u),fy=find_anc(e[i].v);
    39         if(fx==fy&&!cir[fx])ans+=e[i].w,cir[fx]=1;
    40         else if(fx^fy&&(!cir[fx]||!cir[fy]))ans+=e[i].w,cir[fy]|=cir[fx],anc[fx]=fy;
    41     }
    42     return printf("%lld
    ",ans),0;
    43 }
    View Code

    法2——费用流:

    这才是我一开始的想法。。。鉴于每个点最多只会被选一次,所以$S$连向所有$(x,y)$以固定费用,流量为$1$,然后每个点向右边$n+m$(代表这么多行和列)连边,剩下应该就不用说了。。。但是这个数据范围我不知道能不能过的说。。

  • 相关阅读:
    Scala泛型
    Tensorflow激活函数
    20181030-4 每周例行报告
    20181023-3 每周例行报告
    20181016-10 每周例行报告
    20181009-9 每周例行报告
    第三周作业(4)——单元测试
    第三周作业(5)——代码规范
    第三周作业(2)——功能测试
    第三周作业(3)——词频统计--效能分析
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11663621.html
Copyright © 2020-2023  润新知