E. Rectangle Painting 2
题意:
给你一个n *n的矩阵,里面有一些棋盘被染成黑色了,现在让你求把所有黑色的矩阵全部染成白色的最小费用是多少?最小费用的计算方式是:min(h,w)。
输入:
输入一个n,和一个m(代表黑色矩阵的个数),然后在输入每一个矩阵的左下角和右上角的坐标。
输出:
最小费用
分析:
由于数据规模庞大,要使费用最小,就是一整行或者一整列包含的黑色格子多一点,这样我们费用就会少一点,那么我们将行和列拆开来看,把黑色格子的行视为一部分,列视为一部分,那么我们要用最少行或列来将整个黑色矩形覆盖,那么就最小点覆盖,用最小的点覆盖所有边,即二分图,我们有一个性质:最大流=最小割=最小点覆盖=最大匹配,所以这里我们可以用Dinic算法来求解这题,复杂度为O(m*n^2),这里的n不是矩阵的大小,而时每个黑色矩阵的坐标,我们首先将所有黑色矩阵矩形离散化一下,设一个超级源点S,从S到所有的黑色矩阵的x坐标建一条流量为X[i+1]-X[i]的边(X[i+1]-X[i]表示这个两个x坐标中间有多少黑色格子),我们在设一个超级汇点T,从T到所有的黑色矩阵的y坐标建一条流量为Y[i+1]-Y[i]的边,然后我们在求一下建x到y的边,这个边怎么建呢?首先我们求出每一个矩阵所对应离散化后的坐标,得到一块连续的区间(矩阵),然后这块矩阵的每一个x到y这边建一条无穷大的边,最后在跑一遍Dinic算法就搞定了。
如果以上不明白自己画一个图就搞定了。
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int MAXN=250+5;
const int MAXM=6e5+5;
const int INF=0x3f3f3f3f;
struct point
{
int x1,y1,x2,y2;
}arr[MAXN];
int X[MAXN<<1],Y[MAXN<<1];
struct node
{
int to,cap,next;
}edges[MAXM];
int head[MAXN<<1],edge;
int iter[MAXN<<1];//当前弧优化
int level[MAXN<<1];//分层
int vis[MAXN<<1][MAXN<<1];
void init()
{
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
edge=0;
}
void addedges(int u,int v,int cap)
{
edges[edge].to=v;
edges[edge].cap=cap;
edges[edge].next=head[u];
head[u]=edge++;
edges[edge].to=u;
edges[edge].cap=0;
edges[edge].next=head[v];
head[v]=edge++;
}
bool bfs(int s,int t)
{
memset(level,-1,sizeof(level));
level[s]=1;
queue<int>que;
que.push(s);
while(!que.empty())
{
int u=que.front();
que.pop();
for(int i=head[u];i!=-1;i=edges[i].next)
{
int v=edges[i].to;
int cap=edges[i].cap;
if(cap>0&&level[v]<0)
{
level[v]=level[u]+1;
if(v==t)return true;
que.push(v);
}
}
}
return level[t]!=-1;
}
int dfs(int s,int t,int f)
{
if(s==t)return f;
for(int &i=iter[s];i!=-1;i=edges[i].next)
{
int v=edges[i].to;
int cap=edges[i].cap;
if(cap>0&&level[v]==level[s]+1)
{
int d=dfs(v,t,min(f,cap));
if(d>0)
{
edges[i].cap-=d;
edges[i^1].cap+=d;
return d;
}
}
}
return 0;
}
int Dinic(int s,int t)
{
int ans=0;
while(bfs(s,t))
{
memcpy(iter,head,sizeof(iter));
while(int d=dfs(s,t,INF))ans+=d;
}
return ans;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
int num=0;
init();
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%d",&arr[i].x1,&arr[i].y1,&arr[i].x2,&arr[i].y2);
X[num]=--arr[i].x1;
Y[num++]=--arr[i].y1;
X[num]=arr[i].x2;
Y[num++]=arr[i].y2;
}
X[num]=Y[num++]=0;
X[num]=Y[num++]=n;
sort(X,X+num);
int tot_x=unique(X,X+num)-X;
sort(Y,Y+num);
int tot_y=unique(Y,Y+num)-Y;
int s=210,t=215;
for(int i=0;i<tot_x-1;i++)
{
addedges(s,i+1,X[i+1]-X[i]);
}
for(int i=0;i<tot_y-1;i++)
{
addedges(i+tot_x,t,Y[i+1]-Y[i]);
}
for(int i=1;i<=m;i++)
{
int x1=lower_bound(X,X+tot_x,arr[i].x1)-X;
int y1=lower_bound(Y,Y+tot_y,arr[i].y1)-Y;
int x2=lower_bound(X,X+tot_x,arr[i].x2)-X;
int y2=lower_bound(Y,Y+tot_y,arr[i].y2)-Y;
for(int j=x1;j<x2;j++)
{
for(int k=y1;k<y2;k++)
{
vis[j+1][k+1]=1;
}
}
}
for(int i=0;i<tot_x-1;i++)
{
for(int j=0;j<tot_y-1;j++)
{
if(vis[i+1][j+1])
{
addedges(i+1,j+tot_x,INF);
}
}
}
printf("%d\n",Dinic(s,t));
}
return 0;
}