bzoj3175[Tjoi2013] 攻击装置

题目链接:bzoj3175

题目大意:

给定一个01矩阵,其中你可以在0的位置放置攻击装置。每一个攻击装置(x,y)都可以按照“日”字攻击其周围的 8个位置(x-1,y-2),(x-2,y-1),(x+1,y-2),(x+2,y-1),(x-1,y+2),(x-2,y+1), (x+1,y+2),(x+2,y+1)
求在装置互不攻击的情况下,最多可以放置多少个装置。


题解:

最大点独立集

%hyc
因为是日字形,所以可以根据x+y的奇偶性来分二分图。把能互相攻击到的连边,问最多能放多少个就是要求最大点独立集,构完图跑匈牙利求最大匹配然后用点数减一减就好了。

为什么我跑得比hyc慢那么多qwq

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 41000

int fx[8]={1,-1,1,-1,2,-2,2,-2};
int fy[8]={2,2,-2,-2,1,1,-1,-1};
struct node
{
	int x,y,next;
}a[maxn*8];int first[maxn],len;
int ask[maxn],bf[maxn],tim;
int m,ln[maxn],num[300][300];
void ins(int x,int y)
{
	++len;a[len].x=x;a[len].y=y;
	a[len].next=first[x];first[x]=len;
}
int ffind(int x)
{
	for (int i=first[x];i!=-1;i=a[i].next)
	{
		int y=a[i].y;
		if (ask[y]!=tim)
		{
			ask[y]=tim;
			if (bf[y]==-1 || ffind(bf[y]))
			{
				bf[y]=x;
				return true;
			}
		}
	}
	return false;
}
int main()
{
	int n,i,j,k,sum;
	int ans;char s[250];
	scanf("%d\n",&n);
	len=sum=0;
	for (i=1;i<=n;i++)
	{
		gets(s);
		for (j=0;j<n;j++)
		 if (s[j]=='0') {num[i][j+1]=++sum;bf[sum]=-1;}
		 else num[i][j+1]=-1;
	}
	memset(first,-1,sizeof(first));
	for (i=1;i<=n;i++)
	 for (j=1;j<=n;j++)
	  if (num[i][j]!=-1 && !((i+j)&1))
	  {
		for (k=0;k<8;k++)
		 if (i+fx[k]>=1 && i+fx[k]<=n && j+fy[k]>=1 && j+fy[k]<=n && num[i+fx[k]][j+fy[k]]!=-1)
		  ins(num[i][j],num[i+fx[k]][j+fy[k]]);
		m++;ln[m]=num[i][j];
	  }
	ans=tim=0;
	memset(ask,0,sizeof(ask));
	// memset(bf,-1,sizeof(bf));
	for (i=1;i<=m;i++)
	{
		tim++;
		if (ffind(ln[i])) ans++;
	}
	ans=sum-ans;
	printf("%d\n",ans);
	return 0;
}


posted @ 2017-02-22 13:46  OxQ  阅读(153)  评论(0编辑  收藏  举报