HDU 1045 Fire Net

有暴力搜索和二分图匹配两种解题思路。用dfs搜比较容易,而二分图则是一种更为优化的算法。刚刚接触二分图,发现这种思路很巧妙,以后要多加练习。


下面是dfs求法

#include<iostream>
#include<string.h>
using namespace std;
char map[5][5];
int visitr[5];   //记录横坐标
int visitl[5];   //记录纵坐标
int maxn,mm;     //mm是每次搜索的结果,maxn记录最大的
int n;
void dfs(int id)
{
    if(id>n*n)
    {
        if(maxn<mm)
            maxn=mm;
        return;
    }
    int r=(id+n-1)/n;    //将id转化为坐标
    int l=id%n;
    if(l==0)
        l=n;
    if(map[r][l]=='X')   //遇到墙时,以后的行列又可以使用了
    {
        visitr[r]=0;
        visitl[l]=0;

    }
    // 遇到空地有用或不用两种选择
    if(map[r][l]!='X'&&visitr[r]==0&&visitl[l]==0)  //用
    {
        visitr[r]=1;
        visitl[l]=1;
        mm++;

        dfs(id+1);
        mm--;
        visitr[r]=0;
        visitl[l]=0;
    }
    dfs(id+1);  //不用
}
int main()
{
    while(cin>>n&&n)
    {
        maxn=0;
        mm=0;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                cin>>map[i][j];
            }
        }
        memset(visitr,0,sizeof(visitr));
        memset(visitl,0,sizeof(visitl));
        dfs(1);
        cout<<maxn<<endl;
    }
}

下面是二分图匹配。可以使用的原因是本题可以将行和列分成两部分,并且需要一个行对应一个列,刚好符合二分图的性质。

//主函数外的部分都是模版
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
int uN,vN;
int visit[100],use[100];
int g[100][100];
char map[5][5];
int r[5][5];
int l[5][5];
bool dfs(int u)
{
    for(int i=1;i<=vN;i++)
    {
        if(!use[i]&&g[u][i])
        {
            use[i]=true;
            if(visit[i]==-1||dfs(visit[i]))
               {
                   visit[i]=u;
                   return true;
               }
        }
    }
    return false;
}
int hungary()
{
    int res=0;
    memset(visit,-1,sizeof(visit));
    for(int i=1;i<=uN;i++)
    {
        memset(use,0,sizeof(use));
        if(dfs(i))
            res++;
    }
    return res;
}
int main()
{
    int i,j,n;
    while(cin>>n&&n)
    {
        memset(l,0,sizeof(l));
        memset(r,0,sizeof(r));
        memset(g,0,sizeof(g));
        //该处以下是缩点部分,需要自己手动写,最终目的得到g[][]
        for(i=1;i<=n;i++)
           for(j=1;j<=n;j++)
           {
               cin>>map[i][j];
               if(map[i][j]=='X')
                  l[i][j]=r[i][j]=-1;
           }
           uN=0;vN=0;
           for(i=1;i<=n;i++)  //合并行
              for(j=1;j<=n;j++)
              {
                  if(r[i][j]!=-1&&j<=n)
                    uN++;
                  while(r[i][j]!=-1&&j<=n)
                  {
                      r[i][j]=uN;
                      j++;
                  }
              }
          for(j=1;j<=n;j++)   //和并列
             for(i=1;i<=n;i++)
             {
                  if(l[i][j]!=-1&&i<=n)
                    vN++;
                  while(l[i][j]!=-1&&i<=n)
                  {
                      l[i][j]=vN;
                      i++;
                  }
             }
         for(i=1;i<=n;i++)    //得到g[][]
            for(j=1;j<=n;j++)
            {
                if(r[i][j]!=-1)
                  g[r[i][j]][l[i][j]]=1;
            }
         printf("%d\n",hungary());
    }
    return 0;
}



你可能感兴趣的:(HDU,1045Fire,Netdfs二)