zoukankan      html  css  js  c++  java
  • P3355 骑士共存问题【洛谷】(二分图最大独立集变形题) //链接矩阵存图

     展开

    题目描述

    在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘上某些方格设置了障碍,骑士不得进入

    对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击

    输入格式

    第一行有 2 个正整数n 和 m (1<=n<=200, 0<=m<n2),分别表示棋盘的大小和障碍数。接下来的 m 行给出障碍的位置。每行 2 个正整数,表示障碍的方格坐标。

    输出格式

    将计算出的共存骑士数输出

    输入输出样例

    输入
    3 2
    1 1
    3 3

     输出:

    5

    思路:本题显然不存在唯一一行对应唯一一列(車的放置)的关系,那么我们将每个“日”字的对角线进行连接 表示这两个端点无法共存。原题转化为:如何去掉最少的点,去掉所有的边

    等效于点数-最小点覆盖。那么引出:最大独立集=n-最小点覆盖

    类似于【Asteroids POJ - 3041 【最小点覆盖集】】的思想。先求出除了障碍物以外每一个点所能到达的点【到达的点不能是障碍物】。然后在两个相互能到达的点集中 求最小点覆盖{即删掉最小的点使得删掉所有的边【套模板】 }(求出的答案  注意 ans/2   因为是相互的)。然后再套公式:最大独立集=n-最小点覆盖即可。

    AC代码:

     1 #include<bits/stdc++.h>
     2 
     3 //最大独立集=n-最小点覆盖
     4 using namespace std;
     5 #define maxn 666
     6 int dx[]={1,1,2,2,-1,-1,-2,-2};
     7 int dy[]={2,-2,1,-1,2,-2,1,-1};
     8 int mp[maxn][maxn];
     9 int match[666*666];
    10 int vis[666*666];
    11 vector<int> v[666*666*3];
    12 int num[maxn][maxn];
    13 int flag=0;
    14 int n,m;
    15 int head[maxn*maxn];
    16 inline int read(){
    17     char c = getchar(); int x = 0, f = 1;
    18     while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    19     while(c >= '0' & c <= '9') x = x * 10 + c - '0', c = getchar();
    20     return x * f;
    21 }
    22 struct Edge{
    23     int to,next;
    24 }e[666*666*4];
    25 void  add(int u,int v){
    26     flag++;
    27     e[flag].to=v;
    28     e[flag].next=head[u];
    29     head[u]=flag;
    30 } 
    31 int dfs(int u){
    32     for(int i=head[u];i;i=e[i].next){
    33         int temp=e[i].to;
    34         if(!vis[temp]){
    35             vis[temp]=1;
    36             if(match[temp]==0||dfs(match[temp]))
    37             {
    38                 match[temp]=u;
    39                 return 1;
    40             }
    41         }
    42     }
    43     return 0;
    44 } 
    45 void ok(int x,int y){
    46     for(int i=0;i<8;i++){
    47         int tx=x+dx[i];
    48         int ty=y+dy[i];
    49         if(tx>0&&ty>0&&tx<=n&&ty<=n&&!mp[tx][ty]){
    50             //v[num[x][y]].push_back(num[tx][ty]);
    51             //v[num[tx][ty]].push_back(num[x][y]);
    52             add(num[x][y],num[tx][ty]);
    53             add(num[tx][ty],num[x][y]);
    54         }
    55     }
    56 }
    57 int main(){
    58     //int n,m;
    59     //scanf("%d%d",&n,&m);
    60     n=read();
    61     m=read();
    62     for(int i=1;i<=m;i++){
    63         int x,y;
    64         //scanf("%d%d",&x,&y);
    65         x=read();y=read();
    66         mp[x][y]=1;// 标记不可以走到的点 
    67     }
    68     int cnt=0;
    69     for(int i=1;i<=n;i++)
    70         for(int j=1;j<=n;j++)
    71             num[i][j]=++cnt;        // 给每一个点编号 
    72     for(int i=1;i<=n;i++){
    73         for(int j=1;j<=n;j++){
    74             if(mp[i][j])
    75                 continue;
    76             else{
    77                 ok(i,j);
    78             }
    79         }
    80     }
    81     //memset(match,0,sizeof(match));
    82     int ans=0;
    83     for(int i=1;i<=cnt;i++){
    84     //    memset(vis,0,sizeof(vis));
    85         for(int i=0;i<=cnt;i++)
    86             vis[i]=0;
    87         if(dfs(i))
    88             ans++;
    89     }
    90     int res=n*n-m-ans/2;
    91     printf("%d
    ",res);
    92     return 0;
    93 } 
  • 相关阅读:
    css样式表中的样式覆盖顺序(转)
    1.2 明确你的 前端学习路线 和 方法
    1.1 开篇:重新理解前端
    3_1:语言基础:原始值 与 引用值
    2_5:语言基础:语句
    2_4:语言基础:操作符
    2_3:语言基础:数据类型
    2_2:语言基础:变量
    2_1:语言基础:语法
    1_2 HTML中的JavaScript
  • 原文地址:https://www.cnblogs.com/pengge666/p/11626148.html
Copyright © 2011-2022 走看看