题解 P3882 【[JLOI2008]将军】
(我不知道我前面那位哥们怎么跑到如此快的 我猜他是打表过的,因为仅有的一篇题解教唆你去打表。。)
考虑二分图匹配。非常迷的一点是Dinic跑不过但是匈牙利可以。
首先因为斜行不好做,所以处理的时候把棋盘转45°。
然后我们对于每个单位,在原有的攻击范围内添加上一个Bishop的攻击范围,这样可以使得每个单位都不被它攻击。
然后判定哪些格子不会被攻击到,可以二分图匹配了。
建二分图的时候把坐标转换为转45°之后的图再建图。行列匹配。
代码写的很好懂,可以看一下。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<iterator>
#include<queue>
#include<cmath>
#include<vector>
#include<cstdlib>
using namespace std;
struct ed
{
int pre,to;
}edge[1000010]={0,0};
int at=1,ptr[10010]={0},matchs[10010],vis[10010],ansf;
int n,m,mapsiz;
char mapx[2200][2200]={0};
bool av[2200][2200]={0},l[2200]={0},h[2200]={0};
int pau[2200][2]={0};
int wx[8]={0,-1,-1,-1,0,1,1,1},wy[8]={-1,-1,0,1,1,1,0,-1};
int KX[8]={-1,-2,-2,-1,1,2,2,1},KY[8]={-2,-1,1,2,2,1,-1,-2};
inline void Insert(int fx,int tx)
{
at++;
edge[at].pre=ptr[fx];
edge[at].to=tx;
ptr[fx]=at;
}
inline bool Find(int x,int src)
{
for (int prex=ptr[x];prex;prex=edge[prex].pre) if (vis[edge[prex].to]!=src)
{
vis[edge[prex].to]=src;
if (!matchs[edge[prex].to] || Find(matchs[edge[prex].to],src)) { matchs[edge[prex].to]=x; return true; }
}
return false;
}
inline void BuildG()
{
int _x,_y;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) if (!av[i][j])
{
_x=pau[i][0]+j-1; _y=pau[i][1]+j-1;
if ((!h[_x]) && (!l[_y])) Insert(_x,_y+mapsiz);
}
}
inline void GoB(int _x,int _y)
{
av[_x][_y]=true;
int i=pau[_x][0]+_y-1,j=pau[_x][1]+_y-1;
h[i]=true; l[j]=true;
}
inline void GoK(int _x,int _y)
{
GoB(_x,_y);
for (int w=0;w<=7;w++) av[_x+wx[w]][_y+wy[w]]=true;
}
inline void GoQ(int _x,int _y)
{
int wayx[4]={0,-1,0,1},wayy[4]={-1,0,1,0};
GoB(_x,_y);
for (int w=0;w<=3;w++) for (int i=1;;i++)
{
if (mapx[_x+wayx[w]*i][_y+wayy[w]*i]!='.') break;
av[_x+wayx[w]*i][_y+wayy[w]*i]=true;
}
}
inline void GoN(int _x,int _y)
{
GoB(_x,_y);
for (int w=0;w<=7;w++) if (_x+KX[w]>0 && _y+KY[w]>0) av[_x+KX[w]][_y+KY[w]]=true;
}
int main()
{
scanf("%d%d",&n,&m);mapsiz=2*max(n,m)-1;
for (int i=1;i<=n;i++) scanf("%s",mapx[i]+1);
pau[1][0]=1; pau[1][1]=m;
for (int i=2;i<=n;i++) { pau[i][0]=pau[i-1][0]+1; pau[i][1]=pau[i-1][1]-1; }
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
if (mapx[i][j]=='.') continue;
switch (mapx[i][j])
{
case 'K':
GoK(i,j);
break;
case 'Q':
GoQ(i,j);
break;
case 'R':
GoQ(i,j);
break;
case 'B':
GoB(i,j);
break;
case 'P':
GoB(i,j);
break;
case 'N':
GoN(i,j);
break;
}
}
BuildG();
for (int i=1;i<=mapsiz;i++) ansf+=Find(i,i);
printf("%d\n",ansf);
return 0;
}