Codeforces1198 E. Rectangle Painting 2(网络流,二分图最小点权覆盖)

题意:

有一个n*n的矩阵,其中有m块子矩阵是黑色的.

一次操作你可以选择一个子矩阵,将它涂成白色,
假设子矩阵的边长为h*w,那么代价为min(h,w)。
问将所有黑色格子变成白色的最小代价。

数据范围:n<=1e9,m<=50,给定的子矩阵可能相交

解法:

因为代价是对h和w取min,
那么选择一个矩形可以拆分为选择若干行或者列,显然这样最优,
那么问题可以转化为,一次操作可以选择一行或者一列,
用最少的操作次数,将所有黑点覆盖.
这是一个典型的二分图最小点覆盖问题.
但是题目里面给的不是黑点,而是黑块,
黑点的数量可能特别多,如果暴力建图肯定不行.

可以将每一个黑块看作一个黑点,也就是进行离散化,
这样之后每个黑点需要的操作次数就不是1,而是min(h,w),
那么问题就不是最小点覆盖而是最小点权覆盖了,
用网络流解决.
建图:
S->行点,边权为行宽
列点->T,边权为列宽
行点->对应列点,边权inf

关于代码中矩阵左上角坐标为什么要减1:
把坐标变成左闭右开,
例如有区间[2,3][4,5],实际上这两个区间是连接的,
将它改成(1,3](3,5],这样中间3的位置就相交了,
离散化之后只有1,3,5而不是1,2,4,5
那么两区间代价直接就可以(3-1)(5-3),即相邻差值,比较方便
如果不这样做,代价为(3-2+1)(5-4+1),而且没有(4-3+1),需要判断
(当然,也可以是右端点+1)

code:

#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define ll long long
//#define ull unsigned long long
typedef pair<int,int> PI;
const int maxm=1e5+5;
struct Dinic{
    static const int DN=1e5+5;
    static const int DM=4e5+5;
    static const long long inf=1e15;
    int head[DN],nt[DM],to[DM];
    long long w[DM],cnt=1;
    int d[DN];
    int st,ed;
    long long maxflow;
    int idx;
    void init(){
        for(int i=0;i<=idx;i++)head[i]=0;
        cnt=1;
        idx=0;
    }
    void add(int x,int y,long long z){
        cnt++;nt[cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;
    }
    void add2(int x,int y,long long z){
        idx=max(idx,max(x,y));
        add(x,y,z);
        add(y,x,0);
    }
    bool bfs(){
        queue<int>q;
        q.push(st);
        for(int i=0;i<=idx;i++)d[i]=0;
        d[st]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=nt[i]){
                int v=to[i];
                if(w[i]&&!d[v]){
                    d[v]=d[x]+1;
                    q.push(v);
                    if(v==ed)return 1;
                }
            }
        }
        return 0;
    }
    long long dfs(int x,long long flow){
        if(x==ed)return flow;
        long long res=flow;
        for(int i=head[x];i;i=nt[i]){
            int v=to[i];
            if(w[i]&&d[v]==d[x]+1){
                int k=dfs(v,min(res,(long long)w[i]));
                w[i]-=k;
                w[i^1]+=k;
                res-=k;
                if(!k)d[v]=-1;
                if(!res)break;
            }
        }
        return flow-res;
    }
    long long dinic(){
        maxflow=0;
        while(bfs()){
            maxflow+=dfs(st,inf);
        }
        return maxflow;
    }
}G;
struct Node{
    int x,y,xx,yy;
    void input(){
        scanf("%d%d%d%d",&x,&y,&xx,&yy);
    }
}a[maxm];
int n,m;
int x1[maxm],num1;
int y1[maxm],num2;
signed main(){
    G.init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        a[i].input();
        a[i].x--;
        a[i].y--;
        x1[++num1]=a[i].x;
        x1[++num1]=a[i].xx;
        y1[++num2]=a[i].y;
        y1[++num2]=a[i].yy;
    }
    sort(x1+1,x1+1+num1);
    sort(y1+1,y1+1+num2);
    num1=unique(x1+1,x1+1+num1)-x1-1;
    num2=unique(y1+1,y1+1+num2)-y1-1;
    for(int i=1;i<=m;i++){
        a[i].x=lower_bound(x1+1,x1+1+num1,a[i].x)-x1;
        a[i].xx=lower_bound(x1+1,x1+1+num1,a[i].xx)-x1;
        a[i].y=lower_bound(y1+1,y1+1+num2,a[i].y)-y1;
        a[i].yy=lower_bound(y1+1,y1+1+num2,a[i].yy)-y1;
        for(int x=a[i].x;x<a[i].xx;x++){
            for(int y=a[i].y;y<a[i].yy;y++){
                G.add2(x,y+num1,G.inf);
            }
        }
    }
    G.st=++G.idx;
    G.ed=++G.idx;
    for(int i=1;i<num1;i++){
        G.add2(G.st,i,x1[i+1]-x1[i]);
    }
    for(int i=1;i<num2;i++){
        G.add2(i+num1,G.ed,y1[i+1]-y1[i]);
    }
    ll ans=G.dinic();
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/107840987