首页 > 其他分享 >P3756 [CQOI2017] 老C的方块 解题报告

P3756 [CQOI2017] 老C的方块 解题报告

时间:2024-06-08 16:56:13浏览次数:30  
标签:int 100005 dep link P3756 CQOI2017 id 方块 mp

oj:https://gxyzoj.com/d/gxyznoi/p/P266

又是网格题,考虑染色:

显然可以发现,每一个不合法的图形都可以被染成黄->蓝->特殊边->绿->红,且旋转后同样满足条件

推广到整个棋盘就是:

所以是否可以将颜色编号,然后按照上述方法连边呢?

显然是可以的,若一个格子被填上了方块,则讨厌的形状一定满足如下条件:

  1. 特殊边的两边一定是被填的蓝色和绿色

  2. 蓝色周围有被填的黄色

  3. 红色周围有被填的绿色

将局部打开就是:

所以,如果要满足条件,则有四种方式:

  1. 删除被填的蓝色

  2. 删除被填的绿色

  3. 删除蓝色周围的黄色

  4. 删除绿色周围的红色

所以可以按照如下方式建图(不同的字母表示不同颜色):

此时,最小割就是答案

因为r和c比较大,可以用map记录,要么用二维map,或者用一维转换是要注意x,y的大小是否规范

代码:

#include<cstdio>
#include<map>
#include<algorithm>
#include<queue>
#include<cstring>
#define ll long long
using namespace std;
int c,r,n,s,t,edgenum=1,head[100005];
const int inf=1e9;
map<ll,int> mp;
//x->line y->row
ll id(int x,int y)
{
	return 1ll*x*r-r+y;
}
struct edge{
	int to,nxt,val;
}e[2000006];
void add_edge(int u,int v,int w)
{
	e[++edgenum].nxt=head[u];
	e[edgenum].to=v;
	e[edgenum].val=w;
	head[u]=edgenum;
}
void link(int u,int v,int w)
{
//	printf("%d %d %d\n",u,v,w);
	add_edge(u,v,w);
	add_edge(v,u,0);
}
int dep[100005],cur[100005];
queue<int> q;
bool bfs(int x,int y)
{
	memset(dep,0x7f,sizeof(dep));
	for(int i=0;i<=t;i++) cur[i]=head[i];
	while(!q.empty()) q.pop();
	q.push(x);
	dep[x]=1;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=head[u];i;i=e[i].nxt)
		{
			int v=e[i].to;
			if(e[i].val&&dep[v]>inf)
			{
				dep[v]=dep[u]+1;
				q.push(v);
			}
		}
	}
	if(dep[y]<inf) return 1;
	return 0;
}
int dfs(int u,int flow)
{
	if(u==t||flow==0) return flow;
	int res=flow;
	for(int i=head[u];i&&res;i=e[i].nxt)
	{
		int v=e[i].to,w=e[i].val;
		if(dep[v]==dep[u]+1&&w>0)
		{
			int k=dfs(v,min(res,w));
			res-=k;
			e[i].val-=k;
			e[i^1].val+=k;
		}
	}
	if(res==flow) dep[u]=0;
	return flow-res;
}
int x[100005],y[100005],z[100005],d[100005];
int main()
{
	scanf("%d%d%d",&c,&r,&n);
	s=0,t=n+1;
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&x[i],&y[i],&z[i]);
		d[i]=((x[i]&3)^(y[i]&1));
		mp[id(x[i],y[i])]=i;
	//	printf("%d\n",d[i]);
	}
	for(int i=1;i<=n;i++)
	{
		if(d[i]==0)
		{
			if(y[i]%2==1&&mp[id(x[i]+1,y[i])]&&x[i]<c)
			{
				int j=mp[id(x[i]+1,y[i])];
				link(i,j,min(z[i],z[j]));
			}
			if(y[i]%2==0&&mp[id(x[i]-1,y[i])]&&x[i]>1)
			{
				int j=mp[id(x[i]-1,y[i])];
				link(i,j,min(z[i],z[j]));
			}
		}
		if(d[i]==1)
		{
			link(s,i,z[i]);
			if(y[i]%2==1&&mp[id(x[i]+1,y[i])]&&x[i]<c)
			{
				int j=mp[id(x[i]+1,y[i])];
				link(i,j,inf);
			}
			if(y[i]%2==0&&mp[id(x[i]-1,y[i])]&&x[i]>1)
			{
				int j=mp[id(x[i]-1,y[i])];
				link(i,j,inf);
			}
			if(mp[id(x[i],y[i]-1)]&&y[i]>1)
			{
				int j=mp[id(x[i],y[i]-1)];
				link(i,j,inf);
			}
			if(mp[id(x[i],y[i]+1)]&&y[i]<r)
			{
				int j=mp[id(x[i],y[i]+1)];
				link(i,j,inf);
			}
		}
		if(d[i]==2)
		{
			link(i,t,z[i]);
		}
		if(d[i]==3)
		{
			if(y[i]%2==1&&mp[id(x[i]+1,y[i])]&&x[i]<c)
			{
				int j=mp[id(x[i]+1,y[i])];
				link(i,j,inf);
			}
			if(y[i]%2==0&&mp[id(x[i]-1,y[i])]&&x[i]>1)
			{
				int j=mp[id(x[i]-1,y[i])];
				link(i,j,inf);
			}
			if(mp[id(x[i],y[i]-1)]&&y[i]>1)
			{
				int j=mp[id(x[i],y[i]-1)];
				link(i,j,inf);
			}
			if(mp[id(x[i],y[i]+1)]&&y[i]<r)
			{
				int j=mp[id(x[i],y[i]+1)];
				link(i,j,inf);
			}
		}
	}
	int ans=0;
	while(bfs(s,t))
	{
		ans+=dfs(s,inf);
	}
	printf("%d",ans);
	return 0;
}

标签:int,100005,dep,link,P3756,CQOI2017,id,方块,mp
From: https://www.cnblogs.com/wangsiqi2010916/p/18238741

相关文章

  • 俄罗斯方块
    原题链接题解从小正方形到大正方形,有四个变化方向,分别是左上、右上、右下、左上。分类讨论模拟即可code#include<bits/stdc++.h>usingnamespacestd;intmain(){intn,x,y;cin>>n>>x>>y;puts("Yes");intflag=1;if(x==1){if(y==......
  • D. 方块游戏
    原题链接题解太巧妙了!!!code#include<bits/stdc++.h>usingnamespacestd;intmain(){intn,m;cin>>n>>m;intr=0,b=0,y=0;for(inti=1;i<=n;i++){strings;cin>>s;for(intj=0;s[j];j++......
  • 俄罗斯方块 题解
    题意:矩阵checkmax、矩阵求max,checkmax的值一定比当前矩阵原max大外层线段树每个节点开一棵线段树,每个点记录列的max与checkmax的标记checkmax时:对路过的点的max更新,对完全包含的区间的checkmax标记更新求max时:对路上的checkmax与完全包含的max更新\((a,b......
  • mc模组制作 4.方块与blockbench
    点击再点“b”就可以创建方块啦对于方块模型……如果是正正方方的那种,就选Normal,但如果要做一些不规则的,那就要用到了。(下载:https://github.com/JannisX11/blockbench/releases/download/v4.9.4/Blockbench_4.9.4.exe)打开以后点“创建新模型”新手只用填“文件名”就行......
  • 小游戏——俄罗斯方块(附带超详细源码,复制就可实现效果)
    用web前端基础的知识做个俄罗斯方块玩玩。先来看看实现的效果:俄罗斯方块 复制就可以实现所有效果哦!!!详细代码源码:<!DOCTYPEHTML><html><head><metacharset="utf-8"><title>俄罗斯方块小游戏JS版-孙也</title><script>window.onload=functi......
  • P3756 [CQOI2017] 老C的方块
    原题链接感觉挺有意思的。先简化一下不合法的状况,实际上是如果特殊边两侧都有点,且那两个点的另外三个联通方向上也有至少一个点,就是坏的。相当于是四个限制只要有一个不满足就可以了。于是就可以转化成最小割。按四种限制将点分成四类。特殊边两侧分别是\(1\)类点和\(2\)类......
  • love 2d Lua 俄罗斯方块超详细教程
    源码已经更新在CSDN的码库里:gitclonehttps://gitcode.com/funsion/love2d-game.git一直在找Lua能快速便捷实现图形界面的软件,找了一堆,终于发现love2d是小而美的原生lua图形界面实现的方式。并参考相关教程做了一个更详细的,以便入门。功能如上图,开发过程用了love2d,......
  • Java练手游戏--俄罗斯方块
    Java基础小练手游戏项目:俄罗斯方块简单版使用Java实现俄罗斯方块大概思路:界面设计:使用JavaSwing或JavaFX创建游戏窗口和用户界面。创建一个主窗口类(如GameFrame.java),负责设置窗口大小、标题等属性。设计游戏面板(如GamePanel.java),用于绘制游戏区域、下一个方块预览区、得......
  • P2135 方块消除
    原题链接题解代码量小的离谱,思维难度大的离谱对于两个原本不相邻的同色区域块,历经千辛万苦碰面的场景,我们可以描述成右边的区域块为左边的区域块消除的时候增添了长度设\(dp[i][j][suf]\)代表消除区域\([i,j]\)同时该区域的\(j\)增添了长度\(suf\)但是合并消除不一定......
  • 方块掉落
    方块掉落题目描述最近阿宁对一个名叫“方块掉落”的游戏感兴趣,沉迷于此。每局游戏一开始,有一条无限长的水平线、一个箭头、一个操作序列$t$,没有任何方块。操作序列$t$是一个字符串,仅包含"YBR"三种字符,分别代表颜色黄蓝红。依次按照操作序列$s$掉落不同颜色的方块。如果......