BZOJ3175 [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

一个整数,表示在装置互不攻击的情况下最多可以放置多少个装置。

Sample Input

3
010
000
100

Sample Output

4

HINT

100%数据 N<=200

正解:二分图最大匹配(匈牙利算法)

解题报告:

  显然,被某个点走到的点都不能与它共存,不妨给他们连边,然后求一个二分图最大独立子集。

  二分图最大独立子集就是等于总点数减去匹配数。因为每一次匹配完之后,就会多一条边,意味着边连接的两个点只能选一个,所以就少了一个。

  有所优化的就在于不用memset数组,直接给访问数组一个每次dfs特有的标记即可。

 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #ifdef WIN32
14 #define OT "%I64d"
15 #else
16 #define OT "%lld"
17 #endif
18 using namespace std;
19 typedef long long LL;
20 const int MAXM = 1000011;
21 const int MAXN = 211;
22 int n,ecnt;
23 int yi[4][2]={{1,-2},{2,-1},{1,2},{2,1}};//只处理往右的
24 int first[MAXN*MAXN],to[MAXM],next[MAXM];
25 int a[MAXN][MAXN];
26 int vis[40011];
27 int match[MAXN*MAXN],jilu;
28 int ans,flag,tot;
29
30 inline int getint()
31 {
32        int w=0,q=0;
33        char c=getchar();
34        while((c<‘0‘ || c>‘9‘) && c!=‘-‘) c=getchar();
35        if (c==‘-‘)  q=1, c=getchar();
36        while (c>=‘0‘ && c<=‘9‘) w=w*10+c-‘0‘, c=getchar();
37        return q ? -w : w;
38 }
39
40 inline void link(int x,int y){
41     next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y;
42     next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x;
43 }
44
45 inline bool dfs(int x){
46     for(int i=first[x];i;i=next[i]) {
47     int v=to[i];  if(vis[v]==jilu) continue;
48     vis[v]=jilu;
49     if(!match[v] || dfs(match[v])) {
50         match[v]=x; //match[x]=v;//需要记两次就不需要两边记录了
51         return  true;
52     }
53     }
54     return false;
55 }
56
57 inline void work(){
58     n=getint();  char c;
59     for(int i=1;i<=n;i++)
60     for(int j=1;j<=n;j++){
61         c=getchar();
62         while(c!=‘0‘ && c!=‘1‘) c=getchar();
63         if(c==‘1‘) continue;
64         else tot++;
65         a[i][j]=tot;
66     }
67     int x,y;
68     for(int i=1;i<=n;i++)
69     for(int j=1;j<=n;j++) {
70         if(!a[i][j]) continue;
71         for(int k=0;k<=3;k++) {
72         x=i+yi[k][0]; y=j+yi[k][1];
73         if(x<=0 || y<=0 || x>n || y>n) continue;
74         if(!a[x][y]) continue;
75         link(a[x][y],a[i][j]);
76         }
77     }
78     ans=0;//注意初值
79     for(int i=1;i<=tot;i++) {
80         jilu++;//不用清空,打一个标记即可
81         if( dfs(i) ) ans++;//显然冲突的地方只能放一个
82     }
83     //点数减去最大匹配数即最大独立集
84     printf("%d\n",tot-ans/2);
85 }
86
87 int main()
88 {
89   work();
90   return 0;
91 }
时间: 2024-10-03 14:24:21

BZOJ3175 [Tjoi2013]攻击装置的相关文章

bzoj4808: 马 &amp; bzoj3175: [Tjoi2013]攻击装置 (黑白染色+最小割)

bzoj4808: 马 & bzoj3175: [Tjoi2013]攻击装置 题目:传送门 简要题意: 和n皇后问题差不多,但是这里是每个棋子走日子,而且有些格子不能放棋子.求最多能放多少个棋子. 题解: 双倍经验好评 之前看过机房神犇做...有点印象是最小割. 但是直接割的话不会...要应用到黑白染色: 最开始我想递归染色,也就是取一个开始染,然后递归下去... 波老师说会错ORZ...因为感觉递归的情况不好掌握,有可能会重复染色... 结果有一个肥肠巧妙的方法...直接相邻的染为不同颜色 之

BZOJ4808: 马&amp;BZOJ3175: [Tjoi2013]攻击装置

BZOJ3175 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 一个整数,表示在

bzoj3175: [Tjoi2013]攻击装置&amp;&amp;4808: 马

终于知道为啥网络流这么受欢迎了. 其实就是构个图模板一下的事儿,比较好打是吧. 然后这题网络流黑白染色(其实感觉上匈牙利更加直接好想啊,但是实际上黑白染色给人感觉就是二分图) st连白而ed连黑,流量为1 不能同时出现的就建无限流量的边 然后sum-最小割 #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #inc

BZOJ 3175: [Tjoi2013]攻击装置( 匈牙利 )

黑白染成二分图, 然后不能同时选的就连边, 最大匹配数为m, t为不能放的数目, 则题目所求最大点独立集为 n*n-m-t ------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 209; con

[TJOI2013] 攻击装置

3175: [Tjoi2013]攻击装置 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1326  Solved: 636[Submit][Status][Discuss] 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

BZOJ 3175 Tjoi2013 攻击装置 二分图最大匹配

题目大意:给定一个n*n的网格图,要在0的位置上放置一些攻击装置,其中一个攻击装置的攻击范围是周围8个"日"字形区域,要求不能互相攻击,求最多放置多少个攻击装置 每两个能互相攻击且能放置的点连一条双向边,然后跑二分图最大点独立集即可 4W个点n^2居然没TLE 是数据太弱还是匈牙利算法太强了? #include<cstdio> #include<cstring> #include<iostream> #include<algorithm>

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 一个整数,表示在装置互不攻击的情

【bzoj3175】[Tjoi2013]攻击装置

每两个能互相攻击且能放置的点连一条双向边,然后跑二分图最大点独立集即可 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> using namespace std; typedef long long LL; #define M 80010 #define N 210 st

【最大独立集】BZOJ3175- [Tjoi2013]攻击装置

[题目大意] 给定一个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).求在装置互不攻击的情况下,最多可以放置多少个装置. [思路] 最大独立集=总点数-最大二分图匹配 我们都知道最大独立集一般用在二分图里…所以把每个点看作两个点,一个是从它出发,一个是抵达它.实际操作的时候因为