HDU 1045 Fire Net(二分图匹配或爆搜)

 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1045

       题意是有个n*n地图,地图中有空地'.'和墙'X',然后我们要在空地上安置大炮,为了防止大炮打大炮,一行和一列上只能有一台大炮,问最多能放多少大炮。

       比较好想的思路就是爆搜,我们用dfs去一个一个搜,然后判断这行和这列是否已经出现过了,因为数据范围不大,所以搜索可过。还有一种方法感觉挺不好想的,我们按行和列去将块压缩成点,也就是说没有被墙隔开的点都压缩成一个点,然后我们用这些行和列的压缩点去连边,这样我们可以发现相同的行的压缩点和相同列的压缩点上就只能放置一个大炮了,主要就是这伊迪安不太好理解,建议在纸上将两个压缩的图画出来,然后两个压缩后的图进行连边,最后跑一个最大匹配数就好了。


AC代码(爆搜):

#include 
#define maxn 15
using namespace std;
string str[maxn];
int n,ans;

bool Check(int x,int y){    // 判断这个点之前的行和列是否放置过
  for(int i=x-1;i>=0;i--){
    if(str[i][y] == 'X'){
      break;
    }
    if(str[i][y] == 'O') return false;
  }
  for(int i=y-1;i>=0;i--){
    if(str[x][i] == 'X'){
      break;
    }
    if(str[x][i] == 'O'){
      return false;
    }
  }
  return true;
}

void dfs(int cnt, int xx){  // cnt用来枚举地图 xx表示放置的数量
  if(cnt == n * n){
    ans = max(ans, xx);
    return ;
  }
  int x = cnt / n;    // 行
  int y = cnt % n;    // 列
  if(str[x][y] == '.' && Check(x, y)){
    str[x][y] = 'O';
    dfs(cnt + 1, xx + 1);
    str[x][y] = '.';
  }
  dfs(cnt + 1, xx);
}

int main()
{
  while(~scanf("%d",&n)){
    if(n == 0) break;
    for(int i=0;i>str[i];
    }
    ans = 0;
    dfs(0, 0);
    printf("%d\n",ans);
  }
  return 0;
}

 

AC代码(二分图):

#include 
#define maxn 15
using namespace std;
string str[maxn];
int xx[maxn][maxn], yy[maxn][maxn];
bool edge[maxn][maxn], vis[maxn];
int pre[maxn];
int n, row, col;

bool dfs(int x){       // 匈牙利算法
  for(int i=1;i<=col;i++){
    if(edge[x][i] && vis[i] == false){
      vis[i] = true;
      if(pre[i] == -1 || dfs(pre[i])){
        pre[i] = x;
        return true;
      }
    }
  }
  return false;
}

int Fun(){
  int sum = 0;
  memset(pre,-1,sizeof(pre));
  for(int i=1;i<=row;i++){      // 从1开始
    memset(vis,false,sizeof(vis));
    if(dfs(i))
      sum ++;
  }
  return sum;
}

int main()
{
  while(~scanf("%d",&n)){
    if(n == 0) break;
    for(int i=0;i>str[i];
    row = col = 0;
    for(int i=0;i

 

你可能感兴趣的:(ACM_搜索,ACM_二分图)