zoukankan      html  css  js  c++  java
  • 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
    ",tot-ans/2);
    85 }
    86 
    87 int main()
    88 {
    89   work();
    90   return 0;
    91 }
  • 相关阅读:
    模板学习系列(一)tuple
    apue读书笔记第十章
    在亚马逊上关于设计模式的一个评论
    编程珠玑笔记第12章习题
    编程珠玑第14章
    C#,.Net经典面试题目及答案
    sql where 1=1和 0=1 的作用(junyuz)
    快速排序算法
    一道面试题(C#实现了超大整数的加减乘法运算)
    数据结构实验之链表一:顺序建立链表
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5721769.html
Copyright © 2011-2022 走看看