zoukankan      html  css  js  c++  java
  • 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;
    	}
    
  • 相关阅读:
    odoo开发笔记 -- 新建模块扩展原模块增加菜单示例
    div内部div居中
    Css中!important的用法
    SQLServer日期格式转换
    jquery中innerheight outerHeight()与height()的区别
    简单明了区分escape、encodeURI和encodeURIComponent
    PDF预览之PDFObject.js总结
    PDFObject.js,在页面显示PDF文件
    System.IO.Directory.GetCurrentDirectory与System.Windows.Forms.Application.StartupPath的用法
    angular 模块 @NgModule的使用及理解
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9756163.html
Copyright © 2011-2022 走看看