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

Posted 蒟蒻zht的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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 }
View Code

 

以上是关于[luoguP3355] 骑士共存问题(二分图最大独立集)的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 [P3355] 骑士共存问题

luogu P3355 骑士共存问题

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

P3355 骑士共存问题最小点覆盖网络流24题

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

Codevs1922骑士共存问题(最小割,二分图最大匹配)