【CODEVS】1922 骑士共存问题

算法】二分图最大匹配(最大流)

【题解】按(i+j)奇偶性染色后,发现棋子跳到的地方刚好异色。

然后就是二分图了,对于每个奇点向可以跳到的地方连边,偶点不需连(可逆)。

所以题目要求转换为求二分图上最大独立集(对于每条边,至少有一个点不被选中)。

最大独立集=总点数-最小割

//代码略
//hzwer's code:



#include<iostream>
#include<cstdio>
#include<cstring>
#define INF 0x7fffffff
using namespace std;
int n,m,bl,wt,ans,cnt=1;
bool del[201][201];
int mark[201][201];
int xx[8]={1,1,2,2,-1,-1,-2,-2},
    yy[8]={2,-2,1,-1,2,-2,1,-1};
struct data{int to,next,v;}e[500001];
int head[40002],h[40002];
void insert(int u,int v,int w)
{
     cnt++;
     e[cnt].to=v;
     e[cnt].next=head[u];
     head[u]=cnt;
     e[cnt].v=w;
     cnt++;
     e[cnt].to=u;
     e[cnt].next=head[v];
     head[v]=cnt;
 }
void build()
{
     for(int i=1;i<=n;i++)
         for(int j=1;j<=n;j++)
             if(del[i][j])continue;
             else if(mark[i][j]<bl)
             {
             for(int k=0;k<8;k++)
             {
                     int nowx=i+xx[k],nowy=j+yy[k];
                     if(nowx<1||nowy<1||nowx>n||nowy>n||del[nowx][nowy])continue;
                     insert(mark[i][j],mark[nowx][nowy],INF);
                     }
             insert(0,mark[i][j],1);
             }
             else insert(mark[i][j],wt,1);
 }
bool bfs()
{
     int q[40002],t=0,w=1,i,now;
     memset(h,-1,sizeof(h));
     h[0]=q[0]=0;
     while(t<w)
     {
               now=q[t];t++;
               i=head[now];
               while(i)
               {
                       if(h[e[i].to]==-1&&e[i].v){h[e[i].to]=h[now]+1;q[w++]=e[i].to;}
                       i=e[i].next;
                       }
               }
     if(h[wt]==-1)return 0;
     return 1;
 }
int dfs(int x,int f)
{
    if(x==wt)return f;
    int i=head[x];
    int w,used=0;
    while(i)
    {
            if(e[i].v&&h[e[i].to]==h[x]+1)
            {
                w=f-used;
                w=dfs(e[i].to,min(w,e[i].v));   
                e[i].v-=w;
                e[i^1].v+=w;
                used+=w;
                if(used==f)return f;                      
                }
                i=e[i].next;
            }
    if(!used)h[x]=-1;
    return used;
    }
void dinic(){while(bfs()){ans+=dfs(0,INF);}}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
            int x,y;
            scanf("%d%d",&x,&y);
            del[x][y]=1;
            }
    bl=1,wt=(n*n+1)/2+1;
    for(int i=1;i<=n;i++)
       for(int j=1;j<=n;j++)
          if((i+j)%2==0){mark[i][j]=bl;bl++;}
          else {mark[i][j]=wt;wt++;}
    build();
    dinic();
    printf("%d",n*n-m-ans);
    return 0;
}
View Code

 

posted @ 2017-03-03 21:41  ONION_CYC  阅读(405)  评论(0编辑  收藏  举报