zoukankan      html  css  js  c++  java
  • 宫廷守卫

    题目链接:

      P1263 宫廷守卫

    solution:

      欲解决此题,我们先来看一个简化版的问题.有$n$行$m$列的矩阵,每行每列只能放一个士兵,试问最多能放多少个士兵.这种题目是最经典的二分图最大匹配问题,考虑到每行每列均只能放一只兵,我们不妨建立两部分点,第一部分为行,第二部分为列,行列之间的边流量表示此行此列可放一只兵,然后每行每列只能放一只这个条件直接通过超源超汇限流控制即可.

      回到本题,只需将连续的小行小列编上号,即可转化为上述问题.

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<map>
    #include<set>
    #include<vector>
    #define R register
    #define next kdjadskfj
    #define debug puts("mlg")
    #define mod 998244353
    #define Mod(x) ((x%mod+mod)%mod)
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    inline ll read();
    inline void write(ll x);
    inline void writeln(ll x);
    inline void writesp(ll x);
    ll n,m;
    ll Map[210][210];
    ll vis1[210][210],vis2[210][210],cnt,tot1,tot2;
    ll fid[210*210*2];
    ll S,T;
    namespace Dinic{
        ll c[1000000],to[1000000],head[1000000],next[1000000],tot=1;
        
        inline void add(ll x,ll y,ll z){
            to[++tot]=y;next[tot]=head[x];head[x]=tot;c[tot]=z;
        }
        inline void Link(ll x,ll y,ll z){
            add(x,y,z);add(y,x,0);
        }
        
        ll d[1000000];
        queue<ll>q;
        inline bool bfs(){
            memset(d,0,sizeof d);
            while(!q.empty())q.pop();
            q.push(S);d[S]=1;
            while(!q.empty()){
                ll x=q.front();
                q.pop();
                for(R ll i=head[x],ver;i;i=next[i]){
                    ver=to[i];
                    if(!d[ver]&&c[i]){
                        q.push(ver);
                        d[ver]=d[x]+1;
                        if(ver==T) return true;
                    }
                }
            }
            return false;
        }    
        inline ll dinic(ll x,ll flow){
            if(x==T||!flow) return flow;
            ll rest=flow,k;
            for(R ll i=head[x],ver;i&&rest;i=next[i]){
                ver=to[i];
                if(d[ver]==d[x]+1&&c[i]){
                    k=dinic(ver,min(c[i],rest));
                    if(!k) d[ver]=0;
                    rest-=k;
                    c[i]-=k;
                    c[i^1]+=k;
                }
            }
            return flow-rest;
        }
        inline void solve(){
            ll ans=0,_flow;
            while(bfs()){
                while(_flow=dinic(S,0x7fffffff)) ans+=_flow;
            }
            writeln(ans);
            for(R ll i=1;i<=tot1;i++){
                for(R ll j=head[i],ver;j;j=next[j]){
                    ver=to[j];
                    if(ver>cnt) continue;
                    if(!c[j]) writesp(fid[i]),writeln(fid[ver]);
                }
            }
            exit(0);
        }
    }
    int main(){
        n=read();m=read();
        for(R ll i=1;i<=n;i++){
            for(R ll j=1;j<=m;j++){
                Map[i][j]=read();
            }
        }
        for(R ll i=1;i<=n;i++){
            Map[i][0]=2;
            for(R ll j=1;j<=m;j++){
                if(Map[i][j]==2) continue;
                if(Map[i][j-1]==2) vis1[i][j]=++cnt,fid[cnt]=i;
                else vis1[i][j]=cnt;
            }
        }
        tot1=cnt;
        for(R ll i=1;i<=m;i++){
            Map[0][i]=2;
            for(R ll j=1;j<=n;j++){
                if(Map[j][i]==2) continue;
                if(Map[j-1][i]==2) vis2[j][i]=++cnt,fid[cnt]=i;
                else vis2[j][i]=cnt;
            }
        }
        tot2=cnt;
        S=cnt+1;T=S+1;
        for(R ll i=1;i<=tot1;i++){
            Dinic::Link(S,i,1);
        }
        for(R ll i=tot1+1;i<=tot2;i++){
            Dinic::Link(i,T,1);
        }
        for(R ll i=1;i<=n;i++){
            for(R ll j=1;j<=m;j++){
                if(!Map[i][j]) Dinic::Link(vis1[i][j],vis2[i][j],1);
            }
        }
        Dinic::solve();
        
    }
    inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;}
    inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');}
    inline void writesp(ll x){write(x);putchar(' ');}
    inline void writeln(ll x){write(x);putchar('
    ');}
  • 相关阅读:
    .NET 事件模型教程(一)
    [转帖]Predicate的用法
    MSBuild入门(续)
    浅析C# 中object sender与EventArgs e
    调用一个按钮的Click事件(利用反射)
    Delegate,Action,Func,匿名方法,匿名委托,事件
    投票系统如何防止一个用户多次投票
    如何发送表单
    SharePoint NLB选Unicast还是选Multicast?
    为SharePoint的多台WFE配置Windows自带的NLB遇到的一个问题
  • 原文地址:https://www.cnblogs.com/ylwtsq/p/13493096.html
Copyright © 2011-2022 走看看