首先是题目链接  http://codevs.cn/problem/1922/

结果发现题目没图(心情复杂

然后去网上扒了一张图

大概就是这样了。

如果把每个点和它可以攻击的点连一条边,那问题就变成了求二分图的最大独立集了 (二分图最大独立集:即一个点集,集合中任两个结点不相邻),然后就是建图了。

题图非常好心的帮忙染色了,所以我们可以看出来,一个点可以到达的点和它的颜色是不一样的,所以只需要黑白染色就可以了,然后把黑点看作一个集合, 白点看作一个集合,又因为二分图最大独立集=顶点总数 - 最大匹配,而后我们就只需要求最大匹配就可以了。

最大匹配最经典的就是匈牙利啦,但是网络流也可以做, 而且dinic在边容量为一的时候跑得特别快,所以就用dinic了(顺便练习一下dinic233

建图方法:超级源S连接所有的黑点,且边的容量为1, 黑点连接它所有能攻击到的白点,边的容量为INF, 然后所有的白点再连接超级汇T, 容量仍然是为1。跑一遍dinic就可以了(建图的正确性可以自己画图证明

  1. #include <cstdio>
  2. #include <vector>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <queue>
  6. #include <iostream>
  7. using namespace std;
  8. const int N = ;
  9.  
  10. int n, m, cnt, w;
  11.  
  12. struct Edge{
  13. int from, to, cap, flow;
  14. };
  15. vector < int > G[N*N];
  16. vector < Edge > edge;
  17. bool vis[N*N];
  18. int s, t, d[N*N], cur[N*N], INF = (<<), flag[N][N];
  19. int py[][] = {{, }, {, -}, {-, }, {-, -}, {, }, {, -}, {-, }, {-, -}};
  20.  
  21. inline void read(int &ans){
  22. static char buf = getchar();
  23. register int neg = ;
  24. ans = ;
  25. for (;!isdigit(buf); buf = getchar())
  26. if (buf == '-') neg = -;
  27. for (;isdigit(buf); buf = getchar())
  28. ans = ans* + buf - '';
  29. ans *= neg;
  30. }
  31.  
  32. inline void Add(int from, int to, int cap){
  33. edge.push_back((Edge){from, to, cap, });
  34. edge.push_back((Edge){to, from, , });
  35. int m = edge.size();
  36. G[from].push_back(m - );
  37. G[to].push_back(m - );
  38. }
  39.  
  40. bool ok(int x, int y){
  41. if (x > && x <= n && y > && y <= n)
  42. if (flag[x][y] != -)
  43. return true;
  44. return false;
  45. }
  46.  
  47. inline void build(){
  48. for (int i = ; i <= n; i++)
  49. for (int j = ; j <= n; j++)
  50. if (flag[i][j] == -) continue;
  51. else if (flag[i][j] < cnt){
  52. for (int k = ; k < ; k++){
  53. int x = i + py[k][];
  54. int y = j + py[k][];
  55. if (ok(x, y))
  56. Add(flag[i][j], flag[x][y], INF);
  57. }
  58. Add(, flag[i][j], );
  59. }
  60. else Add(flag[i][j], w, );
  61. }
  62.  
  63. inline bool BFS(){
  64. memset(vis, , sizeof(vis));
  65. memset(d, 0xff, sizeof(d));
  66. queue < int > q;
  67. q.push(s);
  68. d[s] = ;
  69. vis[s] = ;
  70. while(!q.empty()){
  71. int u = q.front(); q.pop();
  72. for (int i = ; i < G[u].size(); i++){
  73. Edge& e = edge[G[u][i]];
  74. if (!vis[e.to] && e.cap > e.flow){
  75. d[e.to] = d[u] + ;
  76. vis[e.to] = ;
  77. q.push(e.to);
  78. }
  79. }
  80. }
  81. return vis[t];
  82. }
  83.  
  84. int dfs(int x, int a){
  85. if (x == t || a == ) return a;
  86. int flow = , f;
  87. for (int& i = cur[x]; i < G[x].size(); i++){
  88. Edge& e = edge[G[x][i]];
  89. if (d[x] + == d[e.to] && (f = dfs(e.to, min(e.cap - e.flow, a))) > ){
  90. e.flow += f;
  91. edge[G[x][i]^].flow -= f;
  92. flow += f;
  93. a -= f;
  94. if (a == ) break;
  95. }
  96. }
  97. return flow;
  98. }
  99.  
  100. inline int dinic(){
  101. int ans = ;
  102. while(BFS()){
  103. memset(cur, , sizeof(cur));
  104. ans += dfs(, INF);
  105. }
  106. return ans;
  107. }
  108.  
  109. int main(){
  110. read(n); read(m);
  111. for (int i = ; i < m; i++){
  112. int x, y;
  113. read(x); read(y);
  114. flag[x][y] = -;
  115. }
  116. cnt = ;
  117. w = (n * n + )/ + ;
  118. for (int i = ; i <= n; i++)
  119. for (int j = ; j <= n; j++)
  120. if ((i + j)% == ){
  121. if (flag[i][j] != -) flag[i][j] = cnt;
  122. cnt++;
  123. }
  124. else{
  125. if (flag[i][j] != -) flag[i][j] = w;
  126. w++;
  127. }
  128. s = , t = n*n + ;
  129. build();
  130. printf("%d", n*n - m - dinic());
  131. return ;
  132. }

然而这道题最开始写的时候TLE了

然后就加了当前弧优化

然后就A了(滑稽

但是可以看得出来非常的慢

测试点#kni0.in 结果:AC 内存使用量: 1512kB 时间使用量: 1ms 
测试点#kni1.in 结果:AC 内存使用量: 1388kB 时间使用量: 1ms 
测试点#kni10.in 结果:AC 内存使用量: 7256kB 时间使用量: 415ms 
测试点#kni2.in 结果:AC 内存使用量: 1516kB 时间使用量: 1ms 
测试点#kni3.in 结果:AC 内存使用量: 1644kB 时间使用量: 1ms 
测试点#kni4.in 结果:AC 内存使用量: 1772kB 时间使用量: 3ms 
测试点#kni5.in 结果:AC 内存使用量: 1772kB 时间使用量: 4ms 
测试点#kni6.in 结果:AC 内存使用量: 1768kB 时间使用量: 2ms 
测试点#kni7.in 结果:AC 内存使用量: 2020kB 时间使用量: 4ms 
测试点#kni8.in 结果:AC 内存使用量: 4444kB 时间使用量: 143ms 
测试点#kni9.in 结果:AC 内存使用量: 11732kB 时间使用量: 927ms

然后上网搜了一下其他的题解,发现其他的代码都跑得很快,然后就把建图方式改了一下

  1. #include <cstdio>
  2. #include <vector>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <queue>
  6. #include <iostream>
  7. using namespace std;
  8. const int N = ;
  9.  
  10. int n, m, cnt, w;
  11.  
  12. struct Edge{
  13. int from, to, cap, flow;
  14. };
  15. vector < int > G[N*N];
  16. vector < Edge > edge;
  17. bool vis[N*N];
  18. int s, t, d[N*N], cur[N*N], INF = (<<), flag[N][N], b[N*N];
  19. int py[][] = {{, }, {, -}, {-, }, {-, -}, {, }, {, -}, {-, }, {-, -}};
  20.  
  21. inline void read(int &ans){
  22. static char buf = getchar();
  23. register int neg = ;
  24. ans = ;
  25. for (;!isdigit(buf); buf = getchar())
  26. if (buf == '-') neg = -;
  27. for (;isdigit(buf); buf = getchar())
  28. ans = ans* + buf - '';
  29. ans *= neg;
  30. }
  31.  
  32. inline void Add(int from, int to, int cap){
  33. edge.push_back((Edge){from, to, cap, });
  34. edge.push_back((Edge){to, from, , });
  35. int m = edge.size();
  36. G[from].push_back(m - );
  37. G[to].push_back(m - );
  38. }
  39.  
  40. bool ok(int x, int y){
  41. if (x > && x <= n && y > && y <= n)
  42. if (flag[x][y] != -)
  43. return true;
  44. return false;
  45. }
  46.  
  47. inline int hash(int i,int j){
  48. return (i - )*n + j;
  49. }
  50.  
  51. inline bool BFS(){
  52. memset(vis, , sizeof(vis));
  53. memset(d, 0xff, sizeof(d));
  54. queue < int > q;
  55. q.push(s);
  56. d[s] = ;
  57. vis[s] = ;
  58. while(!q.empty()){
  59. int u = q.front(); q.pop();
  60. for (int i = ; i < G[u].size(); i++){
  61. Edge& e = edge[G[u][i]];
  62. if (!vis[e.to] && e.cap > e.flow){
  63. d[e.to] = d[u] + ;
  64. vis[e.to] = ;
  65. q.push(e.to);
  66. }
  67. }
  68. }
  69. return vis[t];
  70. }
  71.  
  72. int dfs(int x, int a){
  73. if (x == t || a == ) return a;
  74. int flow = , f;
  75. for (int& i = cur[x]; i < G[x].size(); i++){
  76. Edge& e = edge[G[x][i]];
  77. if (d[x] + == d[e.to] && (f = dfs(e.to, min(e.cap - e.flow, a))) > ){
  78. e.flow += f;
  79. edge[G[x][i]^].flow -= f;
  80. flow += f;
  81. a -= f;
  82. if (a == ) break;
  83. }
  84. }
  85. return flow;
  86. }
  87.  
  88. inline int dinic(){
  89. int ans = ;
  90. while(BFS()){
  91. memset(cur, , sizeof(cur));
  92. ans += dfs(, INF);
  93. }
  94. return ans;
  95. }
  96.  
  97. int main(){
  98. read(n); read(m);
  99. for (int i = ; i < m; i++){
  100. int x, y;
  101. read(x); read(y);
  102. b[hash(x, y)] = ;
  103. }
  104. cnt = ;
  105. s = , t = n*n + ;
  106. for(int i = ; i <= n;i++)
  107. for(int j = ; j <=n; j++){
  108. if(!b[hash(i,j)] && ((i+j)&)){
  109. Add(s, hash(i,j), );
  110. if(i > && j > && !b[hash(i-,j-)])
  111. Add(hash(i,j), hash(i-,j-), INF);
  112. if(i > && j + <= n && !b[hash(i-,j+)])
  113. Add(hash(i,j), hash(i-,j+), INF);
  114. if(i > && j > && !b[hash(i-,j-)])
  115. Add(hash(i,j), hash(i-,j-), INF);
  116. if(i > && j + <= n &&!b[hash(i-,j+)])
  117. Add(hash(i,j), hash(i-,j+), INF);
  118. if(i + <= n && j > && !b[hash(i+,j-)])
  119. Add(hash(i,j), hash(i+,j-), INF);
  120. if(i + <= n && j + <= n && !b[hash(i+,j+)])
  121. Add(hash(i,j), hash(i+,j+), INF);
  122. if(i + <= n && j > && !b[hash(i+,j-)])
  123. Add(hash(i,j), hash(i+,j-), INF);
  124. if(i + <= n && j + <= n && !b[hash(i+,j+)])
  125. Add(hash(i,j), hash(i+,j+), INF);
  126. }
  127. if(!b[hash(i,j)] && !((i+j)&)) Add(hash(i,j), t, );
  128. }
  129.  
  130. printf("%d", n*n - m - dinic());
  131. return ;
  132.  
  133. }

修改之后

测试点#kni0.in 结果:AC 内存使用量: 1640kB 时间使用量: 2ms 
测试点#kni1.in 结果:AC 内存使用量: 1512kB 时间使用量: 2ms 
测试点#kni10.in 结果:AC 内存使用量: 7256kB 时间使用量: 178ms 
测试点#kni2.in 结果:AC 内存使用量: 1512kB 时间使用量: 2ms 
测试点#kni3.in 结果:AC 内存使用量: 1640kB 时间使用量: 2ms 
测试点#kni4.in 结果:AC 内存使用量: 1772kB 时间使用量: 2ms 
测试点#kni5.in 结果:AC 内存使用量: 1772kB 时间使用量: 2ms 
测试点#kni6.in 结果:AC 内存使用量: 1772kB 时间使用量: 2ms 
测试点#kni7.in 结果:AC 内存使用量: 2020kB 时间使用量: 4ms 
测试点#kni8.in 结果:AC 内存使用量: 4568kB 时间使用量: 92ms 
测试点#kni9.in 结果:AC 内存使用量: 11608kB 时间使用量: 52ms

少了一个二维循环 + 减少了常数

结果快了1200ms(一脸懵逼

「CODVES 1922 」骑士共存问题(二分图的最大独立集|网络流)&dinic的更多相关文章

  1. loj #6226. 「网络流 24 题」骑士共存问题

    #6226. 「网络流 24 题」骑士共存问题   题目描述 在一个 n×n\text{n} \times \text{n}n×n 个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上 ...

  2. 「AHOI2014/JSOI2014」骑士游戏

    「AHOI2014/JSOI2014」骑士游戏 传送门 考虑 \(\text{DP}\). 设 \(dp_i\) 表示灭种(雾)一只编号为 \(i\) 的怪物的代价. 那么转移显然是: \[dp_i ...

  3. 【刷题】LOJ 6226 「网络流 24 题」骑士共存问题

    题目描述 在一个 \(\text{n} \times \text{n}\) 个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入. 对于给定的 \(\t ...

  4. 「日常温习」Hungary算法解决二分图相关问题

    前言 二分图的重点在于建模.以下的题目大家可以清晰的看出来这一点.代码相似度很高,但是思路基本上是各不相同. 题目 HDU 1179 Ollivanders: Makers of Fine Wands ...

  5. 洛谷P3355 骑士共存问题 二分图_网络流

    Code: #include<cstdio> #include<cstring> #include<queue> #include<vector> #i ...

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

    用匈牙利tle啊喂?和网络流不都是n^3的吗(匈牙利O(nm), isap O(n^2m) 但是isap实际复杂度很优的(二分图匹配中,dinic是O(sqrt(V)*E),不知道isap是不是一样. ...

  7. 「CH6901」骑士放置

    「CH6901」骑士放置 传送门 将棋盘黑白染色,发现"日"字的两个顶点刚好一黑一白,构成一张二分图. 那么我们将黑点向源点连边,白点向汇点连边,不能同时选的一对黑.白点连边. 当 ...

  8. 「THUWC 2017」随机二分图

    「THUWC 2017」随机二分图 解题思路 : 首先有一个 \(40pts\) 的做法: 前 \(20pts\) 暴力枚举最终的匹配是怎样的,check一下计算方案数,后 \(20pts\) 令 \ ...

  9. # 「NOIP2010」关押罪犯(二分图染色+二分答案)

    「NOIP2010」关押罪犯(二分图染色+二分答案) 洛谷 P1525 描述:n个罪犯(1-N),两个罪犯之间的仇恨值为c,m对仇恨值,求怎么分配使得两件监狱的最大仇恨值最小. 思路:使最大xxx最小 ...

随机推荐

  1. python无线网络安全入门案例

    原文链接:http://www.devx.com/security/Article/34741 翻译:诸神的黄昏 整理校对:玄魂 --- 随着⽆线⽹络在家庭和商业中的普及,新的安全挑战是⽆法避免的.保 ...

  2. JDK中日期和时间的几个常用类浅析(五)

    LocalDateTime   LocalDateTime是JDK8中才引入的类,用来表示不包含时区信息的本地日期和时间.我们可以把LocalDateTime看作是LocalDate和LocalTim ...

  3. 云计算之路-阿里云上:RDS数据库连接数过万引发故障,主备库切换后恢复正常

    非常抱歉!今天 12:03-12:52 ,由于数据库连接数异常突增超过1万,达到了阿里云RDS的最大连接数限制,影响了全站的正常访问.由此给您带来麻烦,请您谅解. 在发现数据库连接数突增的问题后,我们 ...

  4. cassandra高级操作之JMX操作

    需求场景 项目中有这么个需求:统计集群中各个节点的数据量存储大小,不是记录数. 一开始有点无头绪,后面查看cassandra官方文档看到Monitoring章节,里面说到:Cassandra中的指标使 ...

  5. 解锁ORACLE数据库

    1.查找锁定数据库的用户 select username,lock_date from dba_users where username='scott';   2.解锁 alter user scot ...

  6. js对象个人理解及记录

    什么是对象 对象的定义是:无序属性的集合,其属性可以包括基本值.对象或函数. var car = {};   //比如我们拿一块铁造了一辆车,这的名字叫car /建一个空对象 car.length = ...

  7. Linux查看网络端口

    简单的总结一下前段时间学习Linux的成果 查看 TCP 22 端口是否打开1.列出所有端口:[root@Demon proc]# netstat -ntlpActive Internet conne ...

  8. 使用NPOI写入Excel数据(ASP.NET)

    第一次做这个写入数据的功能,研究了下npoi的类 IWorkbook wb = new HSSFWorkbook(); //创建表 ISheet sh = wb.CreateSheet("X ...

  9. Linux -atime、mtime、ctime

    Linux中,文件都有其自身的atime.mtime.ctime,在不同的命令下,各时间发生相应的改变.下面,我们来简单的介绍一下: atime (access time):表示最后一次访问文件或目录 ...

  10. CF IndiaHacks 2016 F Paper task 后缀数组

    题目链接:http://codeforces.com/problemset/problem/653/F 大意是给出一个只包含'('和')'的括号串,求有多少不同的子串是合法的括号串 解法:对于每一个后 ...