[ABC274G] Security Camera 3

liyixin發表於2024-09-27

[ABC274G] Security Camera 3

給你一個 \(n\times m\) 的網格圖,\(n,m\le 300\),每個空地上可以放任意多個任意方向的監控,一個監控視野覆蓋對應方向最長連續空地,問監控覆蓋所有空地最小化監控數量。

對於一個極長的連續空地,我們一定是在邊邊放置一個監控,而且兩邊是一樣的,因此我們只需要考慮放置向右和向上的監控就行了。不需要考慮四個方向。

預處理出所有極長連續空地,一個連續空地我們只會放一個監控。問題變成最小化極長連續空地數量,使得覆蓋所有空地。

顯然一個方向的極長連續空地是互不相交的。因此對於每個空地,我們把它對應的橫向極長連續空地和縱向極長連續空地連一條邊,問題就是求二分圖最小點覆蓋(選擇最少的點覆蓋所有邊)。顯然這是一個二分圖,選擇一個點就是選擇一個極長連續空地建一個監控。每個點必須被橫向或者縱向的極長連續空地覆蓋,所以就是最小點覆蓋問題。

二分圖最小點覆蓋問題可以轉化為網路流最大流問題。源點向所有橫向的點連一條流量為 \(1\) 的邊,所有縱向的點向匯點連一條流量為 \(1\) 的邊,一個點屬於編號為 \(x\) 的橫向區間,同時屬於編號為 \(y\) 的縱向區間,那麼就連一條 \(x\to y\) 的流量為 \(1\) 的邊。

其實中間連的那些邊的流量不一定要設為 \(1\) 設為 \(inf\) 也可以。因為一個空地只會和兩個極大塊有關,所以最多隻會有 \(1\) 的流量經過這條邊。

做完啦!現在分析下時間複雜度。\(n,m\) 同階,時間複雜度是 \(O(n^3)\) 的。

網路流點的數量是 \(O(n^2)\) 的,邊的數量也是 \(O(n^2)\) 的。

時間複雜度證明參考 oiwiki。

p1

因此網路流的複雜度是 \(O(n^2\sqrt{n^2})=O(n^3)\)

code

#include<bits/stdc++.h>
// #define LOCAL
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
using namespace std;
typedef long long ll;
const int N=305,inf=0x3f3f3f3f,M=N*N;
int n,m;
char c[N][N];
int id[2][N][N],s;
struct edge{
    int to,ne,f;
}e[M<<4];
int head[M<<4],cnt=1,cur[M<<4];
void addedge(int u,int v,int val){
    e[++cnt]={v,head[u],val};head[u]=cnt;
}
void adde(int u,int v,int val){
    addedge(u,v,val),addedge(v,u,0);
}
int S,T;
int dep[M<<4];
bool bfs(){
    queue<int> q;
    memset(dep,0,sizeof(dep));
    // memcpy(cur,head,sizeof(head));
    q.push(S);
    dep[S]=1;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        cur[u]=head[u];
        // pf("u %d\n",u);
        for(int i=head[u];i;i=e[i].ne){
            int v=e[i].to,w=e[i].f;
            // pf("v %d\n",v);
            if(dep[v]!=0||w<=0) continue;
            dep[v]=dep[u]+1;
            q.push(v);
        }
    }
    // pf("%d\n",(int)dep[T]!=0);
    return dep[T]!=0;
}
int dfs(int u,int res){
    int flow=0;
    if(u==T||!res) return res;
    for(int &i=cur[u];i;i=e[i].ne){
        int v=e[i].to,w=e[i].f;
        if(dep[v]!=dep[u]+1||!w) continue;
        int fl=min(res,w);
        int x=dfs(v,fl);
        if(x==0) dep[v]=-1;
        res-=x,flow+=x;
        e[i].f-=x,e[i^1].f+=x;
    }
    return flow;
}
int dinic(){
    int flow=0;
    while(bfs()) flow+=dfs(S,inf);
    return flow;
}
int main(){
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("my.out","w",stdout);
    #endif 
    sf("%d%d",&n,&m);
    rep(i,1,n){
        sf("%s",c[i]+1);
    }
    S=1,T=2;s=2;
    rep(i,1,n) {
        rep(j,1,m) {
            if(c[i][j]=='.'){
                if(id[0][i][j-1]) id[0][i][j]=id[0][i][j-1];
                else s++,id[0][i][j]=s,adde(S,s,1);
            }
        }
    }
    rep(j,1,m) {
        rep(i,1,n) {
            if(c[i][j]=='.'){
                if(id[1][i-1][j]) id[1][i][j]=id[1][i-1][j];
                else s++,id[1][i][j]=s,adde(s,T,1);
            }
        }
    }
    rep(i,1,n){
        rep(j,1,m){
            if(c[i][j]=='.') adde(id[0][i][j],id[1][i][j],1);
        }
    }
    pf("%d\n",dinic());
}

相關文章