CodeChef BIBOARD: Binary Board 命题报告

这道题当时有了一点模糊的想法之后,构思了一整天……

题意:

有一\(N \times M\)网格,每一格可以是白色或黑色。令\(B_i\)表示\(i \times i\)的纯黑子网格数量(子网格是指原网格的子矩形,必须连通),\(W_i\)表示\(i \times i\)的纯白子网格数量。给定两个非负整数数组\(CW\)\(CB\),定义这个网格的代价为$$\sum_{i=1}^{\mathrm{min}(N, M)} CB_i \cdot B_i + CW_i \cdot W_i$$
现在网格的有些位置颜色确定,让你给剩下的位置钦定颜色,使代价最大。

\(1 \leq N \cdot M \leq 500\)

思路:

注意到题目可以做这样的变形:
1、如果\(N<M\),把它们交换。
2、令\(SB\)\(CB\)的前缀和,\(SW\)同理。
3、定义下标从\(-M\)\(M\)的数组\(S\),满足:
\(i>0\)\(S_i=SB_i\)
\(i<0\)\(S_i=SW_{-i}\)
4、对每一个格子\((i,j)\),试着确定以\((i,j)\)为左上角的纯色正方形的最大边长。如果该正方形为黑色,记\(l_{i,j}\)等于该最大边长;否则\(l_{i,j}\)等于边长的相反数。
5、目标:最大化\(\sum S_{l_{i,j}}\)

由于\(l_{i,j}\)之间的关系错综复杂,互相制约,考虑使用网络流,并尝试最小割模型。

对于每一个格子\((i,j)\)\(-N\)\(N\)之间的整数\(l\),我们都建立一个点\((i,j,l)\),并按以下方式加边:
1、对于\(l<0\)\((i,j,l) ~~ -> ~~ (i,j,l+1)\),代价为\(inf-S_l\)
2、对于\(l>0\)\((i,j,l-1)~~ ->~~ (i,j,l)\),代价为\(inf-S_l\)
3、\(S~~ ->~~ (i,j,-n)\),代价为\(2 \cdot inf\)
4、\((i,j,n)~~->~~T\),代价为\(2 \cdot inf\)

注意在以上建立的边中,割掉一条边意味着对于\((i,j)\),取\(l_{i,j}\)等于这条边对应的\(l\)。对于颜色已经钦定的点,\((i,j,0)\)的某一侧都取两倍无穷大即可。
在边权上加上\(inf\),是为了保证对于特定的\((i,j)\),在如上所述的所有边中,只会割掉一条。

为了保证盘面合法,我们还要考虑两个约束条件(易证它们是充分必要的):
1、两个颜色不同的纯色正方形不能有公共格子;
2、\(|l_{i,j}|\)必须恰好等于,以\((i,j)\)为左上角的纯色正方形的最大边长。

定义\(dist((i,j),(k,l))=max\{i-k,j-l\}\),则我们可以把第一个约束条件写为:
Rule 1:当\(l_{i,j}>0\)(表示网格\((i,j)\)为黑),对于所有的\(k \leq i\)\(l \leq j\)(表示左上方的所有正方形),有\(l_{k,l}>-dist((i,j),(k,l))\)(表示\((i,j)\)不被白色正方形覆盖)。
Rule 2:当\(l_{i,j}<0\),对于所有的\(k \leq i\)\(l \leq j\),有\(l_{k,l}<dist((i,j),(k,l))\)

而思考发现,第二个约束条件(注意不是Rule 2)等价于:
Rule 3:对于合法的盘面,一定不可能把某一个\(l_{i,j}\)的绝对值增加1(符号不变),而不破坏Rule 1、Rule2。换句话说,所有\(l_{i,j}\)都取到极大值。

考虑如何构图以保证符合这3条规则。

不妨改写一下Rule 1和Rule 2:
Rule 1:\(l_{i,j}>0 \Rightarrow l_{k,l}>-dist((i,j),(k,l))\)
Rule 2:\(l_{i,j}<0 \Rightarrow l_{k,l}<dist((i,j),(k,l))\)
为了强制要求最终的割集满足这两个条件,我们对于所有的\(k \leq i\)\(l \leq j\),连以下两条权值为\(2 \cdot inf\)的边:
1、\((i,j,0)~~->~~(k,l,-dist((i,j),(k,l)))\)
2、\((k,l,dist((i,j),(k,l)))~~->~~(i,j,0)\)
易见经过这样的连边后,如果割集不满足Rule 1或Rule 2,剩下的边中就会存在\(S-T\)路径,割集就不是合法的割集。目的达成。

而对于Rule 3:由于\(CB\)\(CW\)中的数都非负,所以\(SB\)\(SW\)都是不下降序列。那么如果可以把某一个\(l_{i,j}\)的绝对值增加1而不破坏Rule 1、Rule2,我们的最小割(实则为最大流)算法一定可以直接在这里增广一次,得到更优解。于是易证,先前构出的图的任何一组最小割一定满足Rule 3。

综上,\(N \cdot M \cdot inf - MinCut\)就是答案。实践中Dinic在这题上跑得飞快。

代码:

#include <bits/stdc++.h>
using namespace std;
#define inf 10000000000000LL
#define iinf 2000000000
#define linf 1000000000000000000LL
#define ulinf 10000000000000000000ull
#define MOD1 1000000007LL
#define mpr make_pair
typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned long UL;
typedef unsigned short US;
typedef pair < int , int > pii;
clock_t __stt;
inline void TStart(){__stt=clock();}
inline void TReport(){printf("\nTaken Time : %.3lf sec\n",(double)(clock()-__stt)/CLOCKS_PER_SEC);}
template < typename T > T MIN(T a,T b){return a<b?a:b;}
template < typename T > T MAX(T a,T b){return a>b?a:b;}
template < typename T > T ABS(T a){return a>0?a:(-a);}
template < typename T > void UMIN(T &a,T b){if(b<a) a=b;}
template < typename T > void UMAX(T &a,T b){if(b>a) a=b;}
namespace mincut{
	const int S=24666,T=24233;
	struct edge{
		int v,r;
		LL f;
		void set(int V,int R,LL F){
			v=V;r=R;f=F;
		}
	};
	vector < edge > adj[25000];
	int cur[25000],dis[25000];
	void init(){
		int i;
		for(i=0;i<25000;++i) adj[i].clear();
	}
	void addedge(int u,int v,LL f){
		edge T;
		T.set(v,(int)adj[v].size(),f);
		adj[u].push_back(T);
		T.set(u,(int)adj[u].size()-1,0LL);
		adj[v].push_back(T);
	}
	void bfs(){
		queue < int > Q;
		Q.push(S);
		dis[S]=0;
		while(!Q.empty()){
			int i,cv=Q.front();
			Q.pop();
			for(i=0;i<(int)adj[cv].size();++i){
				if(adj[cv][i].f>0LL && dis[adj[cv][i].v]==-1){
					dis[adj[cv][i].v]=dis[cv]+1;
					Q.push(adj[cv][i].v);
				} 
			}
		}
	}
	LL dfs(int ver,LL cap){
		if(ver==T) return cap;
		int i;
		for(i=cur[ver];i<(int)adj[ver].size();++i){
			cur[ver]=i;
			edge &E=adj[ver][i];
			if(E.f>0LL && dis[E.v]>dis[ver]){
				LL ret=dfs(E.v,MIN(cap,E.f));
				if(ret>0LL){
					E.f-=ret;
					adj[E.v][E.r].f+=ret;
					return ret;
				}
			}
		}
		return 0LL;
	}
	LL maxflow(){
		LL ret=0LL,dlt;
		while(1){
			memset(dis,-1,sizeof(dis));
			memset(cur,0,sizeof(cur));
			bfs();
			if(dis[T]==-1) return ret;
			dlt=1LL;
			while(dlt){
				dlt=dfs(S,inf*2LL);
				ret+=dlt;
			}
		}
	}
};
int n,m,stt[505][505],tmp[505][505],cb[505],cw[505];
LL sb[505],sw[505];
int getbit(){
	char c=getchar();
	while(c!='0'&&c!='1'&&c!='?') c=getchar();
	return (c=='?'?-1:(c=='1'));
}
int enc(int i,int j,int k){
	return k*n*m+(i*m)+j;
}
void solve(){
    // inputting start
    // 数据结构记得初始化! n,m别写反!
	mincut::init();
    scanf("%d%d",&n,&m);
	int i,j,k,l;
	for(i=0;i<n;++i){
		for(j=0;j<m;++j){
			stt[i][j]=getbit();
		}
	}
	for(i=0;i<n&&i<m;++i) scanf("%d",cw+i);
	for(i=0;i<n&&i<m;++i) scanf("%d",cb+i);
    #ifdef LOCAL
        TStart();
    #endif
    // calculation start
    // 数据结构记得初始化! n,m别写反!
    if(n>m){
		for(i=0;i<n;++i){
			for(j=0;j<m;++j){
				tmp[j][i]=stt[i][j];
			}
		}
		memcpy(stt,tmp,sizeof(tmp));
		swap(n,m);
	}
	sb[0]=(LL)cb[0];
	sw[0]=(LL)cw[0];
	for(i=1;i<n;++i){
		sb[i]=sb[i-1]+(LL)cb[i];
		sw[i]=sw[i-1]+(LL)cw[i];
	}
	for(i=0;i<n;++i){
		for(j=0;j<m;++j){
			int maxl=MIN(n-i,m-j);
			for(k=0;k<n;++k){
				if(stt[i][j]!=1 && n-k<=maxl)
					mincut::addedge(enc(i,j,k),enc(i,j,k+1),inf-sw[n-k-1]);
				else
					mincut::addedge(enc(i,j,k),enc(i,j,k+1),inf*2LL);
			}
			for(k=0;k<n;++k){
				if(stt[i][j]!=0 && k<maxl)
					mincut::addedge(enc(i,j,n+k),enc(i,j,n+k+1),inf-sb[k]);
				else
					mincut::addedge(enc(i,j,n+k),enc(i,j,n+k+1),inf*2LL);
			}
			mincut::addedge(mincut::S,enc(i,j,0),inf*2LL);
			mincut::addedge(enc(i,j,n*2),mincut::T,inf*2LL);
			for(k=0;k<=i;++k){
				for(l=0;l<=j;++l){
					if(k==i&&l==j) continue;
					int dist=MIN(MAX(i-k,j-l),n);
					mincut::addedge(enc(i,j,n),enc(k,l,n-dist),inf*2LL);
					mincut::addedge(enc(k,l,n+dist),enc(i,j,n),inf*2LL);
				}
			}
		}
	}
	printf("%lld\n",inf*(LL)n*(LL)m-mincut::maxflow());
    #ifdef LOCAL
        TReport();
    #endif
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--) solve();
	return 0;
}
posted @ 2018-06-11 20:12  TianyiQ  阅读(387)  评论(0)    收藏  举报