SSL-ZYC P2624 (洛谷P3355)【24题】骑士共存问题

匿名 (未验证) 提交于 2019-12-03 00:32:02

题目大意:


思路:
这题是真的烦。。。
n<=200的数据很容易让我们想到匈牙利算法,所以就打了一发匈牙利。
然后T了。。。
于是就开始优化。
优化了我2个小时。。。


匈牙利算法(二分图)
不难发现,上图黄色格子不能攻击到其他黄色黄色格子,红色格子不能攻击到其他红色格子。
那么就可以把图以奇偶拆分,形成二分图。
然后枚举每个点一级他可以攻击到的点(增广路)。
最后用总格子数最大匹配=最多能放的骑士个数。


代码:

#include<cstdio> #include<cstring> using namespace std;  const short dx[8]={1,1,-1,-1,2,2,-2,-2}; const short dy[8]={-2,2,-2,2,-1,1,-1,1};  //八个方向 int n,m,sum,eve,odd,g[202][202],link[20002],a[20002][3],xx,yy,f; bool vi[20002],ok[202][202]; char ch;  int read()  //输入流 {     f=0;     while(ch=getchar(),ch<=47||ch>=58);f=(f<<3)+(f<<1)+ch-48;     while(ch=getchar(),ch>=48&&ch<=57) f=(f<<3)+(f<<1)+ch-48;     return f; }  bool find(int x)  //匈牙利 {     int d=0,p=0;     for (int i=0;i<8;i++)     {         xx=a[x][1]+dx[i];         yy=a[x][2]+dy[i];          if(xx<1||xx>n||yy<1||yy>n) continue;  //出界         if(ok[xx][yy]||vi[g[xx][yy]]) continue;  //已经走过         d=g[xx][yy];  //记录         p=link[d];         link[d]=x;         vi[d]=true;         if(find(p)||!p) return true;  //继续找增广路         link[d]=p;     }     return false; }  int main() {     n=read();     m=read();     for (int i=1;i<=m;i++)       ok[read()][read()]=true;     for (int i=1;i<=n;i++)      for (int j=1;j<=n;j++)       if(!ok[i][j])       {           if(!((i+j)&1))            g[i][j]=++odd;  //奇数           else           {               g[i][j]=++eve;  //偶数               a[eve][1]=i;               a[eve][2]=j;           }       }     sum=n*n-m;     for (int i=1;i<=eve;i++)  //枚举偶数点     {         memset(vi,0,sizeof(vi));         if(find(i)) sum--;  //有一种方法就减1     }     printf("%d\n",sum);     return 0; }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!