题解:P16148 [ICPC 2017 NAIPC] Apple Market
lailai0916 · · 题解
题意简述
有
解题思路
先建立最大流模型。源点向每位顾客连容量为其预算的边。顾客向能访问的商店连容量为无穷的边,每家商店向汇点连容量为其库存的边。每个单位流量对应出售一个苹果,因此最大流就是答案。
直接连接顾客与商店会产生
对每组
按矩形大小归纳,每个矩形节点都能将流量送到其内部的所有商店。它不能到达矩形外的商店。拆分出的两个子矩形都在原矩形内,且二者的并等于原矩形。故不会遗漏或引入商店。
设顾客矩形的高为
将顾客节点连向这至多
二次幂矩形节点与内部边的数量均为
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=55;
const int L=6;
const int V=159056;
const int E=1231201;
const ll inf=0x3f3f3f3f3f3f3f3f;
struct Edge
{
int v,nxt;
ll w;
}e[E];
int id[L][L][N][N],pw[L],lg[N];
int hd[V],cur[V],dep[V],que[V],cnt;
ll a[N][N];
void add(int u,int v,ll w)
{
e[cnt]={v,hd[u],w};
hd[u]=cnt++;
e[cnt]={u,hd[v],0};
hd[v]=cnt++;
}
bool bfs(int s,int t)
{
fill(dep,dep+V,-1);
int l=0,r=0;
que[r++]=s;
dep[s]=0;
while(l<r)
{
int u=que[l++];
for(int i=hd[u];i!=-1;i=e[i].nxt)
{
int v=e[i].v;
if(e[i].w&&dep[v]==-1)
{
dep[v]=dep[u]+1;
que[r++]=v;
}
}
}
return dep[t]!=-1;
}
ll dfs(int u,int t,ll f)
{
if(u==t)return f;
ll res=0;
for(int &i=cur[u];i!=-1&&res<f;i=e[i].nxt)
{
int v=e[i].v;
if(!e[i].w||dep[v]!=dep[u]+1)continue;
ll d=dfs(v,t,min(f-res,e[i].w));
if(!d)continue;
e[i].w-=d;
e[i^1].w+=d;
res+=d;
}
if(!res)dep[u]=-1;
return res;
}
ll dinic(int s,int t)
{
ll ans=0;
while(bfs(s,t))
{
copy(hd,hd+V,cur);
ans+=dfs(s,t,inf);
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m,q;
cin>>n>>m>>q;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>a[i][j];
pw[0]=1;
for(int i=1;i<L;i++)pw[i]=pw[i-1]*2;
for(int i=2;i<N;i++)lg[i]=lg[i/2]+1;
int tot=0;
for(int i=0;i<=lg[n];i++)
{
for(int j=0;j<=lg[m];j++)
{
int w=m-pw[j]+1,c=(n-pw[i]+1)*w;
for(int k=0;k<c;k++)id[i][j][k/w+1][k%w+1]=tot++;
}
}
memset(hd,-1,sizeof hd);
int s=tot+q;
for(int i=0;i<q;i++)
{
int x1,x2,y1,y2;
ll x;
cin>>x1>>x2>>y1>>y2>>x;
int p=lg[x2-x1+1],r=lg[y2-y1+1];
int rx[2]={x1,x2-pw[p]+1},cy[2]={y1,y2-pw[r]+1};
int u=tot+i;
add(s,u,x);
for(int j=0;j<2;j++)
{
if(j&&rx[j]==rx[0])continue;
add(u,id[p][r][rx[j]][cy[0]],inf);
if(cy[1]!=cy[0])add(u,id[p][r][rx[j]][cy[1]],inf);
}
}
for(int i=0;i<=lg[n];i++)
{
for(int j=0;j<=lg[m];j++)
{
if(!i&&!j)continue;
int w=m-pw[j]+1,c=(n-pw[i]+1)*w;
for(int k=0;k<c;k++)
{
int x=k/w+1,y=k%w+1,u=id[i][j][x][y];
if(i)
{
add(u,id[i-1][j][x][y],inf);
add(u,id[i-1][j][x+pw[i-1]][y],inf);
}
else if(j)
{
add(u,id[i][j-1][x][y],inf);
add(u,id[i][j-1][x][y+pw[j-1]],inf);
}
}
}
}
int t=s+1;
for(int i=0;i<n*m;i++)add(id[0][0][i/m+1][i%m+1],t,a[i/m+1][i%m+1]);
cout<<dinic(s,t)<<'\n';
return 0;
}