P1521芯片制作
时间限制 : 10000 MS 空间限制 : 65536 KB
问题描述
计算机的大脑通常被称为CPU。
现在国家XX局交给小A一个重要任务,要求他制作一种新型的CPU,幸运的是,CPU研究中心已经将好多个CPU内核蚀刻在硅片上了,这种硅片很可爱,它是由3n^2个内核拼成的L型。当n=5的时候,硅片的形状如下图所示。小A的任务就是把CPU内核从硅片上切割下来,封装在一个铜盒子里拿出来卖钱。
(自行脑补)
由于技术原因,CPU的蚀刻有可能失败,如果某个CPU内核蚀刻失败了,它就不能卖钱了。在上图中,有3个内核蚀刻失败,蚀刻失败的内核的坐标分别是C4,F2,G5。显然,如果硅片上有m个CPU内核蚀刻失败了,则有3n2-m个内核是可以卖钱的,如果每个CPU内只装1个内核(这就是传统的单核处理器),此时你就可以做出3n2-m个CPU。
小A雇用了你来替他完成这个东西。他把所有任务都交给了你。突然,国家发展和改革委员会决定要发展双核处理器技术。你要做的是双核处理器了。上司告诉你,如果在L型硅片上任意两个相邻的CPU内核都是完好的,那么你就可以把它们一起切下来做成一个双核CPU。所谓相邻,指的是CPU内核有一条公共边界。
由于你的薪水是按照做出的CPU的个数决定的,现在你想算算最多能切出多少个双核的CPU。
输入格式
第一行包含2个整数n,k
以下K行,每行包括一个字母和紧跟着的一个整数,代表一个蚀刻失败的CPU的坐标。文件保证坐标在L型硅片内。
输出格式
一行,仅包含一个整数,代表能切出的最多双核CPU个数。
样例输入
2 3
D1
A3
C2
样例输出
4
提示
在100%的数据中2<=n<=7, 0.1n2<=k<=3n^2。
不然一卖就是一两百核,岂不是666
切芯片嘛,就和切蛋糕一样
这个核和它右边的核在一起了,他就不能和它下面那个核在一起(除非它是个渣核)
那条件就很明显了嘛,不就是 一夫一妻制 嘛
把中心核放一边,把以它为中心的另外4个核放在另外一边
这就是一个小的二分图
那么你把这个图放大一点
那你就会发现这是一个交替放边的图,大意如下(1和0代表放在不同边)
1 0 1 0 1 0 1
0 1 0 1 0 1 0
1 0 1 0 1 0 1
0 1 0 1 0 1 0
1 0 1 0 1 0 1
0 1 0 1 0 1 0
1 0 1 0 1 0 1
那不就是交替染个色,然后同色的放同边呗
易得,相同颜色的横纵坐标之和的奇偶性相同
如
1(行)+3(列)=4
1(行)+5(列)=6
2(行)+4(列)=6
这些格子同色,且同偶
所以构图代码如下
int A=0,B=0;
for(int a=1;a<=n;a++)
for(int b=1;b<=n;b++)
map[a][b]=((a+b)%2==0)?++A:++B;
由于我们在增广路的时候,只跑同一种颜色的点(就是在同一边的点)
所以我们读图的时候就是跳着读的,就比如上面那个01图,我们只读1或者只读0,这样求出来的才是最大匹配
于是乎
就有了如下代码
for(int x=1;x<=n;x++)
for(int y=1+(x%2);y<=n;y+=2)//跳着读,如果行数x为奇数,就从第二列开始读,为偶数就从第一列开始读,且隔一个读一个
find(maps[x][y])
①构图时要把坏掉的点标记成0
②可以先构一个2n*2n的图,再把(n+1,n+1)到(2n,2n)的点给黑掉
#include
#include
#include
using namespace std;
int n,k,res=0;
int fath[1234],went[1234];
int all=0,star[1234],ent[1234],nxt[1234];
int maps[23][23];
void add(int s,int e)
{
nxt[++all]=star[s];
star[s]=all;
ent[all]=e;
}
bool find(int s)
{
int bian,e;
for(bian=star[s],e=ent[bian];bian;bian=nxt[bian],e=ent[bian])
if(!went[e])
{
went[e]=1;
if(!fath[e]||find(fath[e]))
{
fath[e]=s;
return 1;
}
}
return 0;
}
int main()
{
char x;int y,A=0,B=0;
scanf("%d%d\n",&n,&k);
for(int a=1;a<=2*n;a++)
for(int b=1;b<=2*n;b++)maps[a][b]=(a+b)%2==1?++A:++B;//染色
while(scanf("%c%d\n",&x,&y)!=EOF)maps[x-'A'+1][y]=0;//删点
for(int a=n+1;a<=(n<<1);a++)
for(int b=n+1;b<=(n<<1);b++)
maps[a][b]=0;
for(int b=1;b<=(n<<1);b++)
for(int a=1+b%2;a<=(n<<1);a=a+2)
if(maps[a][b])
{
if(a-1>=1&&maps[a-1][b])add(maps[a][b],maps[a-1][b]);
if(a+1<=2*n&&maps[a+1][b])add(maps[a][b],maps[a+1][b]);
if(b+1<=2*n&&maps[a][b+1])add(maps[a][b],maps[a][b+1]);
if(b-1>=1&&maps[a][b-1])add(maps[a][b],maps[a][b-1]);
}//构图
for(int b=1;b<=2*n;b++)
for(int a=1+b%2;a<=n*2;a=a+2)//读取同色的点
if(maps[a][b])
{
memset(went,0,sizeof(went));
if(find(maps[a][b]))res++;
}
printf("%d",res);
}