Fire Net HDU && NYOJ blockhouses

Link Here..ANDLink Here

题意:大体上就是叫你在一张图中,确定几个位置,是存放机枪的数目达到最多。

分析:该题与经典的八皇后问题相似,只是该问题比八皇后问题多了有墙的限制,存放的位置多了一些选择。该题可以用搜索做但也可以用二分图做。因为该题的数据较少,所以搜索和二分图并无太大的区别。

先说一下搜索:

#include <stdio.h>
char map[5][5];
int ans,n;
bool Judg(int x,int y)//判断方法类似于八皇后问题
{
    bool ok = false;  //判断在同一水平直线上是否形成了对峙的机枪
    map[x][y] = 'F';
    for(int j = 0;j < n;j++)
    {
        if(map[x][j] == 'F')
        {
            if(ok)return false;
            else ok = true;
        }
        if(map[x][j] == 'X')ok = false;
    }
    ok = false;
    for(int i = 0;i < n;i++)
    {
        if(map[i][y] == 'F')
        {
            if(ok)return false;
            else ok = true;
        }
        if(map[i][y] == 'X')ok = false;
    }
    return true;
}
void DFS(int x,int y,int cnt)
{
    if(cnt>ans)ans = cnt;
    if(y == n){x++;y = 0;}
    if(x == n)return ;
    if(map[x][y] == 'X'){
      DFS(x,y+1,cnt);
    }else
    {
        if(Judg(x,y))
          DFS(x,y+1,cnt+1);
        map[x][y] = '.';
        DFS(x,y+1,cnt);
    }
}
int main()
{
    while(scanf("%d",&n),n)
    {
        for(int i = 0;i < n;i++)
          scanf("%s",map[i]);
        ans = 0;
        DFS(0,0,0);
        printf("%d\n",ans);
    }
    return 0;
}


 

二分图:

二分图最要是建图有一定的难度,话说我还没有完全的理解该题的建图真正含义。但正如楼教主说的,“虽然,我不懂这道题,但AC还是没问题的”。一下是借用他人博客的话。

建图方法:横竖分区。先看每一列,同一列相连的空地同时看成一个点,显然这样的区域不能够同时放两个点。这些点作为二分图的X部。同理在对所有的行用相同的方法缩点,作为Y部。

连边的条件是两个区域有相交部分。最后求最大匹配就是答案。

#include<stdio.h>
#include<string.h>
int n,RowN,ColN;
bool used[20];
char map[5][5];
int g[20][20],link[20],Row[5][5],Col[5][5];
int Find(int u)
{
    for(int v = 1;v <= ColN;v++)
        if(g[u][v]&&!used[v])
        {
            used[v]=true;
            if(link[v]==-1||Find(link[v]))
            {
                link[v]=u;
                return 1;
            }
        }
    return 0;
}
int Hungary()
{
    int ans = 0;
    memset(link,-1,sizeof(link));
    for(int u=1;u<=RowN;u++)
    {
        memset(used,0,sizeof(used));
        ans += Find(u);
    }
    return ans;
}
int main()
{
    while(scanf("%d",&n),n)
    {
        memset(Row,0,sizeof(Row));
        memset(Col,0,sizeof(Col));
        memset(g,0,sizeof(g));
        for(int i = 0;i < n;i++)
        {
            scanf("%s",map[i]);
            for(int j = 0;j < n;j++)if(map[i][j]=='X')
               Row[i][j] = Col[i][j] = -1;
        }
        int i,j,cnt=0;
        RowN = ColN = 0;
        for(i=0;i<n;i++)
          for(j=0;j<n;j++)
          {
              while(Row[i][j]==-1&&j<n)j++;
              cnt ++;
              while(Row[i][j]!=-1&&j<n)
              {
                 Row[i][j]=cnt;
                 j++;
              }
              if(RowN<cnt)RowN=cnt;
           }   //printf("Row=%d\n",RowN);
           for(cnt=j=0;j<n;j++)
             for(i=0;i<n;i++)
             {
                 while(Col[i][j]==-1&&i<n)i++;
                 cnt ++;
                 while(Col[i][j]!=-1&&i<n)
                 {
                     Col[i][j]=cnt;
                    i++;
                 }
                 if(ColN<cnt)ColN=cnt;
             }   //printf("vN=%d\n",ColN);
          for(i=0;i<n;i++)
            for(j=0;j<n;j++)if(Row[i][j]!=-1&&Col[i][j]!=-1)
              g[Row[i][j]][Col[i][j]]=1;
         printf("%d\n",Hungary());
    }
    return 0;
}


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值