P4304 [TJOI2013]攻击装置
题意描述:
给你一个\(0,1\) 矩阵,可以在 \(0\) 位置放攻击装置,每个位置可以攻击到一些地方。
问你最多可以放多少个攻击装置使得这几个攻击装置互不攻击。
solution:
我们对于这个位置以及这个位置可以攻击到的位置连边。
问题就转化为了求二分图的最大独立集。
二分图的最大独立集等于总点数减去最大匹配数。
匈牙利算法或者网络流求解即可。
如果使用匈牙利算法求解的话,注意一开始要 \(dfs\) 一遍,找到左侧的边。
成功的跑到了泥古 \(rk2\) .
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 40000;
int n,cnt,ans,top,tot;
int head[N],sta[N],match[N],col[N],id[510][510];
bool vis[N],used[N];
char s[510][510];
int dx[8] = {-1,-2,1,2,-1,-2,1,2};
int dy[8] = {-2,-1,-2,-1,2,1,2,1};
struct node
{
int to,net;
}e[2000010];
void add(int x,int y)
{
e[++tot].to = y;
e[tot].net = head[x];
head[x] = tot;
}
void DFS(int x,int c)//二分图染色,把左侧的点找出来
{
col[x] = c; vis[x] = 1;
if(c == 1) sta[++top] = x;
for(int i = head[x]; i; i = e[i].net)
{
int to = e[i].to;
if(!col[to]) DFS(to,3-c);
}
}
bool dfs(int x)
{
for(int i = head[x]; i; i = e[i].net)
{
int to = e[i].to;
if(!used[to])
{
used[to] = 1;
if(!match[to] || dfs(match[to]))
{
match[to] = x;
return 1;
}
}
}
return 0;
}
int main()
{
scanf("%d",&n);
for(int i = 1; i <= n; i++) scanf("%s",s[i]+1);
for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(s[i][j] == '0') id[i][j] = ++cnt;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
if(s[i][j] == '1') continue;
for(int k = 0; k < 8; k++)
{
int x = i + dx[k];
int y = j + dy[k];
if(x < 1 || x > n || y < 1 || y > n) continue;
if(s[x][y] == '0') add(id[i][j],id[x][y]);
}
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
if(s[i][j] == '0' && !col[id[i][j]]) DFS(id[i][j],1);
}
}
for(int i = 1; i <= top; i++)
{
memset(used,0,sizeof(used));
if(dfs(sta[i])) ans++;
}
printf("%d\n",cnt-ans);
return 0;
}