[luoguP3355] 骑士共存问题(二分图最大独立集)

传送门

模型

二分图最大独立集,转化为二分图最大匹配,从而用最大流解决。

实现

首先把棋盘黑白染色,使相邻格子颜色不同。

把所有可用的黑色格子看做二分图X集合中顶点,可用的白色格子看做Y集合顶点。

建立附加源S汇T,从S向X集合中每个顶点连接一条容量为1的有向边,从Y集合中每个顶点向T连接一条容量为1的有向边。

从每个可用的黑色格子向骑士一步能攻击到的可用的白色格子连接一条容量为无穷大的有向边。

求出网络最大流,要求的结果就是可用格子的数量减去最大流量。

分析

用网络流的方法解决棋盘上的问题,一般都要对棋盘黑白染色,使之成为一个二分图。放尽可能多的不能互相攻击的骑士,就是一个二分图最大独立集问题。有关二分图最大独立集问题,更多讨论见《最小割模型在信息学竞赛中的应用》作者胡伯涛。

该题规模比较大,需要用效率较高的网络最大流算法解决。(使用Dinic+当前弧优化)

——代码

  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #define INF 1e9
  6 #define N 1000001
  7 #define min(x, y) ((x) < (y) ? (x) : (y))
  8
  9 int n, m, cnt, tot, sum, s, t;
 10 int map[201][201], head[N], to[N], val[N], next[N], dis[N], cur[N];
 11 int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2},
 12     dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};
 13
 14 inline int read()
 15 {
 16     int x = 0, f = 1;
 17     char ch = getchar();
 18     for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = -1;
 19     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - ‘0‘;
 20     return x * f;
 21 }
 22
 23 inline void add2(int x, int y, int z)
 24 {
 25     to[cnt] = y;
 26     val[cnt] = z;
 27     next[cnt] = head[x];
 28     head[x] = cnt++;
 29 }
 30
 31 inline void add(int x, int y, int z)
 32 {
 33     add2(x, y, z);
 34     add2(y, x, 0);
 35 }
 36
 37 inline bool bfs()
 38 {
 39     int i, u, v;
 40     std::queue <int> q;
 41     memset(dis, -1, sizeof(dis));
 42     q.push(s);
 43     dis[s] = 0;
 44     while(!q.empty())
 45     {
 46         u = q.front(), q.pop();
 47         for(i = head[u]; i ^ -1; i = next[i])
 48         {
 49             v = to[i];
 50             if(val[i] && dis[v] == -1)
 51             {
 52                 dis[v] = dis[u] + 1;
 53                 if(v == t) return 1;
 54                 q.push(v);
 55             }
 56         }
 57     }
 58     return 0;
 59 }
 60
 61 inline int dfs(int u, int maxflow)
 62 {
 63     if(u == t) return maxflow;
 64     int v, d, ret = 0;
 65     for(int &i = cur[u]; i ^ -1; i = next[i])
 66     {
 67         v = to[i];
 68         if(val[i] && dis[v] == dis[u] + 1)
 69         {
 70             d = dfs(v, min(val[i], maxflow - ret));
 71             ret += d;
 72             val[i] -= d;
 73             val[i ^ 1] += d;
 74             if(ret == maxflow) return ret;
 75         }
 76     }
 77     return ret;
 78 }
 79
 80 int main()
 81 {
 82     int i, j, k, x, y;
 83     n = read();
 84     m = read();
 85     s = 0, t = n * n + 1;
 86     memset(head, -1, sizeof(head));
 87     for(i = 1; i <= m; i++)
 88     {
 89         x = read();
 90         y = read();
 91         map[x][y] = -1;
 92     }
 93     for(i = 1; i <= n; i++)
 94         for(j = 1; j <= n; j++)
 95             if(!map[i][j])
 96             {
 97                 map[i][j] = ++tot;
 98                 if((i + j) & 1) add(s, tot, 1);
 99                 else add(tot, t, 1);
100             }
101     for(i = 1; i <= n; i++)
102         for(j = 1; j <= n; j++)
103             if(map[i][j] ^ -1 && (i + j) & 1)
104                 for(k = 0; k < 8; k++)
105                 {
106                     x = i + dx[k];
107                     y = j + dy[k];
108                     if(x >= 1 && x <= n && y >= 1 && y <= n && map[x][y] ^ -1) add(map[i][j], map[x][y], INF);
109                 }
110     while(bfs())
111     {
112         for(i = s; i <= t; i++) cur[i] = head[i];
113         sum += dfs(s, INF);
114     }
115     printf("%d\n", tot - sum);
116     return 0;
117 }

时间: 2024-10-12 19:27:55

[luoguP3355] 骑士共存问题(二分图最大独立集)的相关文章

骑士共存问题(二分图最大独立集)

//http://www.cnblogs.com/IMGavin/ #include <iostream> #include <stdio.h> #include <cstdlib> #include <cstring> #include <queue> #include <vector> #include <map> #include <stack> #include <set> #include

「CODVES 1922 」骑士共存问题(二分图的最大独立集|网络流)&amp;dinic

首先是题目链接  http://codevs.cn/problem/1922/ 结果发现题目没图(心情复杂 然后去网上扒了一张图 大概就是这样了. 如果把每个点和它可以攻击的点连一条边,那问题就变成了求二分图的最大独立集了 (二分图最大独立集:即一个点集,集合中任两个结点不相邻),然后就是建图了. 题图非常好心的帮忙染色了,所以我们可以看出来,一个点可以到达的点和它的颜色是不一样的,所以只需要黑白染色就可以了,然后把黑点看作一个集合, 白点看作一个集合,又因为二分图最大独立集= 二分图最大匹配,

【wikioi】1922 骑士共存问题(网络流/二分图匹配)

用匈牙利tle啊喂?和网络流不都是n^3的吗.... (更新:what!!!!!!发现个无语的问题,.!!!!结构比数组快啊orz,这节奏不对啊....以后图都写结构的节奏啊... #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> using namespace

洛谷 P3355 骑士共存问题

题目描述 在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击 输入输出格式 输入格式: 第一行有 2 个正整数n 和 m (1<=n<=200, 0<=m<n2),分别表示棋盘的大小和障碍数.接下来的 m 行给出障碍的位置.每行 2 个正整数,表示障碍的方格坐标. 输出格式: 将计算出的共存骑士数输出 输入输出样

【网络流24题】 骑士共存

Description 在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入. 对于给定的n*n个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击. Input 第一行有2 个正整数n 和m (1<=n<=200, 0<=m<=n * n)分别表示棋盘的大小和障碍数. 接下来的m 行给出障碍的位置.每行2 个正整数,表示障碍的方格坐标. Output 将计算出的共存骑士数输出 Sampl

[网络流24题] 骑士共存(cogs 746)

骑士共存问题?问题描述:在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘 上某些方格设置了障碍,骑士不得进入. ?编程任务:对于给定的n*n个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击.?数据输入:由文件knight.in给出输入数据.第一行有2 个正整数n 和m (1<=n<=200, 0<=m<=n*n)<n2),< span="">分别表示棋盘的大小和障碍数.接下来的

3175. [TJOI2013]攻击装置【二分图最大独立集】

Description 给定一个01矩阵,其中你可以在0的位置放置攻击装置.每一个攻击装置(x,y)都可以按照“日”字攻击其周围的 8个位置(x-1,y-2),(x-2,y-1),(x+1,y-2),(x+2,y-1),(x-1,y+2),(x-2,y+1), (x+1,y+2),(x+2,y+1) 求在装置互不攻击的情况下,最多可以放置多少个装置. Input 第一行一个整数N,表示矩阵大小为N*N.接下来N行每一行一个长度N的01串,表示矩阵. Output 一个整数,表示在装置互不攻击的情

[网络流24题] 骑士共存

746. [网络流24题] 骑士共存 ★★☆   输入文件:knight.in   输出文件:knight.out   简单对比 时间限制:1 s   内存限制:128 MB 骑士共存问题 «问题描述: 在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘 上某些方格设置了障碍,骑士不得进入. «编程任务: 对于给定的n*n个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑 士,使得它们彼此互不攻击. «数据输入: 由文件knight.in给出输入数据.第一

P3355 骑士共存问题 二分建图 + 当前弧优化dinic

P3355 骑士共存问题 题意: 也是一个棋盘,规则是“马”不能相互打到. 思路: 奇偶点分开,二分图建图,这道题要注意每个点可以跑八个方向,两边都可以跑,所以边 = 20 * n * n. 然后dinic 要用当前弧优化. #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <