• P3355 骑士共存问题


    P3355 骑士共存问题

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

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

    Solution

    二分图最大独立集
    骑士共存是这个的经典模型
    两个点互相干涉的点只能取其一

    定理: 二分图的最大独立集为其点数减去最大匹配数
    证明:
    最大独立集: 最多互不干涉的点
    (Rightarrow) 选出最少的点使得剩下的互不干涉
    (Rightarrow) 选出最多的点覆盖所有干涉边
    而最小点覆盖 (=) 最大匹配数
    故成立
    证毕。

    类似棋盘覆盖问题, 我们将棋盘黑白染色
    发现此点与干涉点属于不同的颜色
    故有干涉关系的连边做二分图最大匹配即可
    此题卡匈牙利算法, 使用最大流

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define LL long long
    #define REP(i, x, y) for(int i = (x);i <= (y);i++)
    using namespace std;
    int RD(){
        int out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const int maxn = 419, maxv = 1000019, INF = 1e9 + 19;
    int head[maxn * maxn],nume = 1;
    struct Node{
        int v,dis,nxt;
        }E[maxv << 3];
    void add(int u,int v,int dis){
        E[++nume].nxt = head[u];
        E[nume].v = v;
        E[nume].dis = dis;
        head[u] = nume;
        }
    int len, num;
    int map[maxn][maxn];
    int mx[8] = {-2,-1, 1, 2, 2, 1,-1,-2};
    int my[8] = {-1,-2,-2,-1, 1, 2, 2, 1};
    bool judge(int x, int y){
    	if(x < 1 || x > len || y < 1 || y > len)return 0;
    	return 1;
    	}
    int id(int x, int y){return (x - 1) * len + y;}
    int s, t, maxflow;
    int d[maxn * maxn];
    bool bfs(){
    	queue<int>Q;
    	memset(d, 0, sizeof(d));
    	d[s] = 1;
    	Q.push(s);
    	while(!Q.empty()){
    		int u = Q.front();Q.pop();
    		for(int i = head[u];i;i = E[i].nxt){
    			int v = E[i].v;
    			if(!d[v] && E[i].dis){
    				d[v] = d[u] + 1;
    				Q.push(v);
    				if(v == t)return 1;
    				}
    			}
    		}
    	return 0;
    	}
    int Dinic(int u, int flow){
    	if(u == t)return flow;
    	int rest = flow, k;
    	for(int i = head[u];i;i = E[i].nxt){
    		int v = E[i].v;
    		if(d[v] == d[u] + 1 && E[i].dis){
    			k = Dinic(v, min(rest, E[i].dis));
    			if(!k)d[v] = 0;
    			E[i].dis -= k;
    			E[i ^ 1].dis += k;
    			rest -= k;
    			if(!rest)break;
    			}
    		}
    	return flow - rest;
    	}
    int main(){
    	len = RD(), num = RD();
    	s = 0, t = maxn * maxn - 19;
    	REP(i, 1, num){
    		int x = RD(), y = RD();
    		map[x][y] = 1;
    		}
    	REP(i, 1, len)REP(j ,1, len){
    		if(map[i][j])continue;
    		int now = id(i, j);
    		if((i + j) % 2 == 1)add(s, now, 1), add(now, s, 0);
    		else add(now, t, 1), add(t, now, 0);
    		}
    	REP(i, 1, len)REP(j ,1, len){
    		if(map[i][j] || (i + j) % 2 == 0)continue;
    		int u = id(i ,j);
    		for(int k = 0;k < 8;k++){
    			int nx = i + mx[k];
    			int ny = j + my[k];
    			if(!judge(nx, ny))continue;
    			if(map[nx][ny])continue;
    			int v = id(nx, ny);
    			add(u, v, 1), add(v, u, 0);
    			}
    		}
    	int flow = 0;
    	while(bfs())while(flow = Dinic(s, INF))maxflow += flow;
    	printf("%d
    ",len * len - maxflow - num);
    	return 0;
    	}
    
  • 相关阅读:
    Js Array 删除
    语音播报功能
    js实现HashTable
    Js 克隆
    获取电脑名和IP地址
    获取电脑名和Ip
    IIS 配置问题
    WCF 服务
    【并查集】wikioi1001舒适的路线
    【实用】读取信息
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9756163.html
Copyright © 2020-2023  润新知