[网络流24题][codevs1922] 骑士共存问题 二分图最大独立集

1922 骑士共存问题

题目描述 Description
在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘
上某些方格设置了障碍,骑士不得进入。

[网络流24题][codevs1922] 骑士共存问题 二分图最大独立集_第1张图片

对于给定的n*n个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑
士,使得它们彼此互不攻击。

输入描述 Input Description
第一行有2 个正整数n 和m (1<=n<=200, 0<=m < n^2),
分别表示棋盘的大小和障碍数。接下来的m 行给出障碍的位置。每行2 个正整数,表示障
碍的方格坐标。

输出描述 Output Description
将计算出的共存骑士数输出

样例输入 Sample Input
3 2
1 1
3 3

样例输出 Sample Output
5

#include
#include
#include
#define INF 0x7fffffff
using namespace std;
const int N = 405;
int n,m,cnt=1,T,ans;
int last[N*N],map[N][N],num,h[N*N],q[N*N],nb[N][N];
int dx[8] = {1,1,2,2,-1,-1,-2,-2};
int dy[8] = {2,-2,1,-1,2,-2,1,-1};
struct Edge{
    int to,v,next;
}e[N*N*4];
void insert( int u, int v, int w ){
    e[++cnt].to = v; e[cnt].v = w; e[cnt].next = last[u]; last[u] = cnt;
    e[++cnt].to = u; e[cnt].v = 0; e[cnt].next = last[v]; last[v] = cnt;
}
bool bfs(){
    int head = 0, tail = 1;
    memset(h,-1,sizeof(h));
    q[0] = 0; h[0] = 0;
    while( head != tail ){
        int now = q[head++]; if( now == T ) return true;
        for( int i = last[now]; i; i = e[i].next )
            if( e[i].v && h[e[i].to] == -1 ){
                h[e[i].to] = h[now] + 1;
                q[tail++] = e[i].to;
            }
    }
    return h[T] != -1;
}
int dfs( int x, int f ){
    if( x == T ) return f;
    int w,used = 0;
    for( int i = last[x]; i; i = e[i].next )
        if( e[i].v && h[e[i].to] == h[x] + 1 ){
            w = dfs( e[i].to, min(f-used,e[i].v) );
            e[i].v -= w; e[i^1].v += w; used += w;
            if( used == f ) return used;
        }
    if( !used ) h[x] = -1;
    return used;
}
void dinic(){
    while(bfs()){
        ans += dfs(0,INF);
    }
}
void build(){
    T = n*n+1;
    for( int i = 1; i <= n; i++ ) for( int j = 1; j <= n; j++ ) nb[i][j] = ++num;
    for( int i = 1; i <= n; i++ )
        for( int j = 1; j <= n; j++ )
            if( !map[i][j] ){
                if( (i+j) % 2 == 0 ){
                    insert(0,nb[i][j],1);
                    for( int k = 0; k < 8; k++ ){
                        int xx = i + dx[k]; int yy = j + dy[k];
                        if( xx < 1 || xx > n || yy < 1 || yy > n || map[xx][yy] ) continue;
                        insert( nb[i][j], nb[xx][yy], 1 );
                    }
                } else{
                    insert( nb[i][j], T, 1 );
                }
            }
}
int main(){
    scanf("%d%d", &n, &m);
    for( int i = 1, x, y; i <= m; i++ ) scanf("%d%d", &x, &y ), map[x][y] = 1;
    build(); dinic();
    printf("%d",n*n-m-ans);
    return 0;
}

你可能感兴趣的:(网络流,二分图,codevs)