题面:
思路:
基本上和方格取数问题差不多
这道题可以证明,如果把每两个不能共存的点连在一起,那么这个图没有奇环,是一个二分图
同时,如果把这个图像国际象棋一样黑白染色,那么连边的两个点颜色不同
源点连黑点,边权为1
黑点连白点,边权为inf
白点连汇点,边权为1
跑出最大流,即为这个图的最小点覆盖
用整张图的点数减去障碍物数量,再减去最大流的值就是答案了
Code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #define inf 0x7fffffff 6 using namespace std; 7 struct erickin{ 8 int to,next,data,rev; 9 }edge[400010]; 10 const int dx[9]={0,-2,-2,-1,-1,1,1,2,2}; 11 const int dy[9]={0,1,-1,2,-2,2,-2,1,-1}; 12 int n,m=0,mm;bool a[210][210]; 13 int first[50010],d[50010]; 14 void add(int op,int ed,int val){ 15 ++m;edge[m].to=ed;edge[m].rev=m+1;edge[m].data=val;edge[m].next=first[op];first[op]=m; 16 ++m;edge[m].to=op;edge[m].rev=m-1;edge[m].data=0;edge[m].next=first[ed];first[ed]=m; 17 } 18 int bfs(int s,int t){ 19 memset(d,-1,sizeof(d)); 20 queue<int>q;int u,v,p; 21 d[s]=0; 22 q.push(s); 23 while(!q.empty()){ 24 u=q.front();p=first[u];q.pop(); 25 // cout<<"in pt "<<u<<endl; 26 while(p!=-1){ 27 v=edge[p].to; 28 // cout<<" going to pt "<<v<<endl; 29 if(d[v]<0&&edge[p].data>0){ 30 // cout<<" success!"<<endl; 31 d[v]=d[u]+1; 32 if(v==t) return 1; 33 q.push(v); 34 } 35 p=edge[p].next; 36 } 37 } 38 return 0; 39 } 40 int dfs(int u,int flow,int ed){ 41 if(u==ed) return flow; 42 int p=first[u],cur=0,v,t; 43 // cout<<"dfs in "<<u<<ends<<flow<<ends<<ed<<endl; 44 while(p!=-1){ 45 v=edge[p].to; 46 // cout<<" to "<<v<<endl; 47 if(edge[p].data>0&&d[v]==d[u]+1&&(t=dfs(v,min(flow-cur,edge[p].data),ed))){ 48 edge[p].data-=t;edge[edge[p].rev].data+=t;cur+=t; 49 if(cur==flow) return flow; 50 } 51 p=edge[p].next; 52 } 53 if(!cur) d[u]=-1; 54 return cur; 55 } 56 void dinic(int s,int t){ 57 int ans=0; 58 while(bfs(s,t)) ans+=dfs(s,inf,t); 59 printf("%d",(((n*n)-mm)-ans)); 60 } 61 int main(){ 62 freopen("knight.in","r",stdin); 63 freopen("knight.out","w",stdout); 64 memset(first,-1,sizeof(first)); 65 scanf("%d%d",&n,&mm); 66 int x1,x2; 67 for(int i=1;i<=mm;i++){ 68 scanf("%d%d",&x1,&x2); 69 a[x1][x2]=1; 70 } 71 for(int i=1;i<=n;i++){ 72 for(int j=1;j<=n;j++){ 73 if(a[i][j]) continue; 74 int now=n*(i-1)+j; 75 if((i+j)%2){ 76 add(0,now,1); 77 for(int k=1;k<=8;k++){ 78 int ti=i+dx[k],tj=j+dy[k]; 79 if(!a[ti][tj]&&0<ti&&ti<=n&&0<tj&&tj<=n){ 80 int now1=n*(ti-1)+tj; 81 add(now,now1,inf); 82 } 83 } 84 } 85 else add(now,n*n+1,1); 86 } 87 } 88 dinic(0,n*n+1); 89 }