• Battle ships HDU


    Battle shipsHDU - 5093

      题目大意:n*m的地图,*代表海洋,#代表冰山,o代表浮冰,海洋上可以放置船舰,但是每一行每一列只能有一个船舰(类似象棋的車),除非同行或者同列的船舰中间有冰山挡着,问最多能放多少个船舰?

      之前做过一个放置炮的,那时数据小直接暴力加搜索就A了,然而这题暴力搜索的话,直接了当的TLE,没办法只好去学新东西了。二分图这个概念只有在之前的题目中做过匈牙利的板子题,可是具体概念和思路并不了解,这题也正好提醒了我去深入了解。但最近需要做的事情较大,一直想整理的一些算法和模板总结也暂时拖一拖。

      回到这题,为什么可以用二分匹配做呢,首先如果没有障碍全是海的话,那就刚好是每一行每一列只能放一个,那我们分配的时候就是给每一行分配一列,这样一行一列刚好对应了放置的位置,而这个给每一行分配一列的过程刚好也可以用二分匹配实现。那么多了障碍之后,该如何处理呢,其实也就是一行分成多行,我们把相同行的统一编号化成一块区域,举个例子,比如2*6的地图

      ******

      ******

      之前每个点对行编号就是

      111111

      111111

      而多了障碍之后

      ***#**

      **#***

      这时的编号就是

      111022

      330444

      列的处理也是类似,列的编号就是

      123056

      120456

      有了编号之后,我们就可以根据共同点连边,像行编号为1的点和列编号为1,2,3的点有公共点,那么它们可以连边。上图每个行块可以连的列块就是

      1:1 2 3

      2:5,6

      3:1,2

      4:4,5,6

      这时我们就是尽可能多的给每一个行快分配一个列块,这样就可以得到最多的点,也就是最多能放置的数目。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<vector>
     4 using namespace std;
     5 char s[52][52];
     6 int x,y,xid[52][52],yid[52][52],cj[520],vis[520];
     7 vector<int> vv[520];
     8 bool match(int u)
     9 {
    10     for(int i=0;i<vv[u].size();i++)
    11     {
    12         int v=vv[u][i];
    13         if(!vis[v])//这个列还没遍历过 
    14         {
    15             vis[v]=1;
    16             if(!cj[v]||match(cj[v]))//这个列块还没分配给某个行块 
    17             {//或者它分配给的行块可以匹配其他列块 
    18                 cj[v]=u;
    19                 return 1;
    20             }
    21         }
    22     }
    23     return 0;
    24 }
    25 int main()
    26 {
    27     int t,n,m;
    28     scanf("%d",&t);
    29     while(t--)
    30     {
    31         scanf("%d%d",&n,&m);
    32         for(int i=0;i<n;i++)
    33             scanf("%s",s[i]);
    34         memset(xid,0,sizeof(xid));
    35         memset(yid,0,sizeof(yid));
    36         x=0,y=0;
    37         for(int i=0;i<n;i++)
    38         {
    39             int j=0,is=0;
    40             while(j<m)
    41             {
    42                 if(s[i][j]=='#')
    43                     is=0;
    44                 while(j<m&&s[i][j]=='#')
    45                     j++;
    46                 if(s[i][j]=='*')
    47                 {
    48                     if(!is)
    49                         x++;                    
    50                     is=1;
    51                     xid[i][j]=x;
    52                 }
    53                 j++;
    54             }
    55         }//给每个行块编号 
    56         for(int i=0;i<m;i++)
    57         {
    58             int j=0,is=0;
    59             while(j<n)
    60             {
    61                 if(s[j][i]=='#')
    62                     is=0;
    63                 while(i<n&&s[j][i]=='#')
    64                     j++;
    65                 if(s[j][i]=='*')
    66                 {
    67                     if(!is)
    68                         y++;
    69                     is=1;
    70                     yid[j][i]=y;
    71                 }
    72                 j++;
    73             }
    74         }//给每个列块编号 
    75         for(int i=0;i<=x;i++)
    76             vv[i].clear();
    77         for(int i=0;i<n;i++)
    78             for(int j=0;j<m;j++)
    79                 if(s[i][j]=='*')//二分图加边 
    80                     vv[xid[i][j]].push_back(yid[i][j]);        
    81         int ans=0;
    82         memset(cj,0,sizeof(cj));
    83         for(int i=1;i<=x;i++)//匈牙利算法模板 
    84         {
    85             memset(vis,0,sizeof(vis));
    86             ans+=match(i);
    87         }
    88         printf("%d
    ",ans);
    89     }
    90     return 0;
    91 } 
    门泊东吴万里船

      感觉二分匹配难在怎么想到这个建边

  • 相关阅读:
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    win10右键新建markdown文件
    force down pool_member
    自控力差,你可能忽略了一种更底层的能力
    多线程的通信问题
    多线程的安全问题
    Java实现多线程的两种方式
    为什么你成不了数据分析高手?可能是缺少这个思维
    jstack && jmap
    对ElasticSearch主副分片的理解
  • 原文地址:https://www.cnblogs.com/LMCC1108/p/10642199.html
Copyright © 2020-2023  润新知