bzoj4823 cqoi2017 老C的方块【最大流】

bzoj4823 cqoi2017 老C的方块【最大流】_第1张图片bzoj4823 cqoi2017 老C的方块【最大流】_第2张图片bzoj4823 cqoi2017 老C的方块【最大流】_第3张图片bzoj4823 cqoi2017 老C的方块【最大流】_第4张图片bzoj4823 cqoi2017 老C的方块【最大流】_第5张图片

看到题目其实感觉很麻烦,不知道从哪里入手,那么仔细观察所给出的有用信息...


我们考虑网格图是一个含有挡板的图,这个挡板的分布很有规律,大概是每一行的相邻两个挡板都隔了四个格子,并且奇数行的排列相同,偶数行的排列相同...


然后考虑不合法的方块形状有什么共同点:仔细观察就会发现,所有的不合法图形中,挡板的左边至少有一个格子,右边至少有一个格子,并且左边的格子连着一个格子,右边的的格子连着一个格子...也就是说,其实我们如果要使得整张图的所有方块构成的图形全部合法就要满足下图中如果挡板两边的紫色格子都有方块存放的话,那么,和这两个紫色格子相邻的色格子和黑色格子不能同时存在...

bzoj4823 cqoi2017 老C的方块【最大流】_第6张图片

我们发现刚好相邻隔板之间的四个格子就是为不合法图案而设计的...

于是就变成了经典的限制问题...经典的最小割...

如果不考虑紫色的格子,那么这整张网格图就是一个二分图...我们给这张图染色...

bzoj4823 cqoi2017 老C的方块【最大流】_第7张图片

那么对于所有的白点,我们连的边,对于所有的黑点我们连的边,然后因为要保证紫色格子周围黑白点不能同时存在,所以,对于所有的黑点,我们从紫色格子像黑点连$inf$的边,从白点像紫色格子连$inf$的边,然后因为我们两个紫色格子不同时存在的时候黑白点是可以同时存在的,所以两个紫色格子之间连min(w[x],w[y])的边...然后求最小割就好了...

注意题目输入是先输列,后输行;

注意两个紫色格子也要分开讨论,所以共有四层,可以发现每个2*4的区域都是一样的,所以可以预处理出颜色;

讨论时要注意不能把边建重了,特别是连源点,会点的边。

#include
#include
#include
#include
#include
#include
#include
using namespace std; 

int getint()
{
	int i=0,f=1;char c;
	for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
	if(c=='-')f=-1,c=getchar();
	for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
	return i*f;
}

const int N=1e5+5,M=2e6+5,INF=0x3f3f3f3f;
const int color[2][4]={2,1,4,3,1,2,3,4};
const int fx[4]={0,1,0,-1};
const int fy[4]={-1,0,1,0};
int r,c,n,cnt,src,des;
int val[N],type[N];
int tot=1,first[N],cur[N],step[N],next[M],to[M],cap[M],from[M];
bool visit[N];
map,int>p;

inline void add(const int &x,const int &y,const int &w)
{
	next[++tot]=first[x],first[x]=tot,to[tot]=y,cap[tot]=w,from[tot]=x;
	next[++tot]=first[y],first[y]=tot,to[tot]=x,cap[tot]=0;
}

inline bool bfs()
{
	static int que[N];
	int tail=1;
	for(int i=src;i<=des;i++)step[i]=-1,cur[i]=first[i];
	que[tail]=src,step[src]=0;
	for(int head=1;head<=tail;head++)
	{
		int u=que[head];
		for(int e=first[u];e;e=next[e])
		{
			int v=to[e];
			if(cap[e]>0&&step[v]==-1)
			{
				step[v]=step[u]+1;
				que[++tail]=v;
				if(v==des)return true;
			}
		}
	}
	return false;
}

inline int dinic(const int &u,const int &flow)
{
	if(u==des)return flow;
	int res=0;
	for(int &e=cur[u];e;e=next[e])
	{
		int v=to[e];
		if(cap[e]>0&&step[v]>step[u])
		{
			int delta=dinic(v,min(flow-res,cap[e]));
			if(delta)
			{
				cap[e]-=delta,cap[e^1]+=delta;
				res+=delta;if(res==flow)break;
			}
		}
	}
	if(res!=flow)step[u]=-1;
	return res;
}

inline int maxflow()
{
	int ans=0;
	while(bfs())ans+=dinic(src,INF); 
	return ans;
}

int main()
{
	//freopen("lx.in","r",stdin);
	r=getint(),c=getint(),n=getint();
	src=0,des=n+1;
	int x,y,u,v;
	for(int i=1;i<=n;i++)
	{
		y=getint(),x=getint(),val[i]=getint();
		p[make_pair(x,y)]=i;
		type[i]=color[x%2][y%4];
	}
	map,int>::iterator it;
	for(it=p.begin();it!=p.end();it++)
	{
		x=it->first.first;
		y=it->first.second;
		u=it->second;
		if(type[u]==3)
			for(int k=0;k<4;k++)
			{
				int nowx=x+fx[k],nowy=y+fy[k];
				if(p.count(make_pair(nowx,nowy)))
				{
					v=p[make_pair(nowx,nowy)];
					if(type[v]==4)
					{
						if(!visit[v])add(src,v,val[v]),visit[v]=true;
						add(v,u,INF);
					}
					if(type[v]==2)
						add(u,v,min(val[u],val[v]));
				}
			}
		if(type[u]==2)
			for(int k=0;k<4;k++)
			{
				int nowx=x+fx[k],nowy=y+fy[k];
				if(p.count(make_pair(nowx,nowy)))
				{
					v=p[make_pair(nowx,nowy)];
					if(type[v]==1)
					{
						if(!visit[v])add(v,des,val[v]),visit[v]=true;
						add(u,v,INF);
					}
				}
			}
	}
	cout<


你可能感兴趣的:(bzoj4823 cqoi2017 老C的方块【最大流】)