• 棋盘问题总结


    我们在研究问题时经常能碰到这一类为题:在某个棋盘上有一种棋子,问最多放下几个棋子。或者有一堆棋子,问你移去最少的棋子数目,使得剩下来的棋子两两不攻击。

    先看下面这道题

    问题 E: P1035

    时间限制: 1 Sec  内存限制: 128 MB
    提交: 82  解决: 35
    [提交][状态][讨论版]

    题目描述

    给出一张n*n(n< =100)的国际象棋棋盘,其中被删除了一些点,问可以使用多少1*2的多米诺骨牌进行掩盖。

    输入

    第一行为n,m(表示有m个删除的格子) 第二行到m+1行为x,y,分别表示删除格子所在的位置 x为第x行 y为第y列 

    输出

    一个数,即最大覆盖格数

    样例输入

    8 0
    

    样例输出

    32

    这道题先想的是状压DP(爆搜)后来不会做啦。

    其实一个棋子只能和它上下左右4块中的一块拼成一大块,所以我们把每个棋子与其上下左右四个棋子连一条边。连完所有的边后,我们发现要求的就是最多有多少的边(顶点不能重复)想到了什么?二分图匹配。但它不一定是个二分图啊。我们需要证明这一点。一种口糊的方法就是显然一个点仅走奇数次肯定不能回到原点,所以原图中不存在奇数边的环路,就是二分图啦。还有一种比较巧妙和通用的方法就是将棋盘黑白染色,所有黑的只能与白点发生关系,就是显然的二分图了(黑白两个点集)。对于棋子的问题,我们只要在相互冲突的棋子连上一条边,然后简单的证明一下是不是二分图,最后求最大子独立集或最大匹配即可。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define grey 2
    #define black 1
    #define white 0
    int sum,n,m,Map[105][105],color[105][105],num_white,num_black,White[105],Black[10005],used[10005],match[10005];
    bool dfs(int u){
          int t,i;
          for (int v=1;v<=num_white;v++)
          {
                  i=White[v];
                  if (used[i]==0 && Map[u][i])
                  {
                              
                            used[i]=1;
                            t=match[i];
                            match[i]=u;
                            if (t==0 || dfs(t)) return 1;
                            match[i]=t;
                 }
                 
              }
          return 0;
    }
    void make_way(int u,int v)
    {
        Map[u][v]=1;
    }
    int make_num(int a,int b)
    {
        return ((n)*(a-1)+b);
    }
    void make_edge()
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            if(color[i][j]!=grey)
            {
                if(color[i][j]==white)
                {
                    White[++num_white]=make_num(i,j);
                }else Black[++num_black]=make_num(i,j);
                if(i>1&&color[i-1][j]!=grey) make_way(make_num(i,j),make_num(i-1,j));
                if(j>1&&color[i][j-1]!=grey) make_way(make_num(i,j),make_num(i,j-1));
                if(i<n&&color[i+1][j]!=grey) make_way(make_num(i,j),make_num(i+1,j));
                if(j<n&&color[i][j+1]!=grey) make_way(make_num(i,j),make_num(i,j+1));
            }
    }
    void draw(int n)
    {
        for(int i=1;i<=n;i++)
        {
            if(i%2) color[i][1]=black;else color[i][1]=white;  
            for(int j=2;j<=n;j++)
            {
                color[i][j]=1^color[i][j-1];
            }
        }
    }
    void print()
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            cout<<color[i][j];
            cout<<endl;
        }
    }
    int main()
    {
        scanf("%d %d",&n,&m);
        draw(n);
        int a,b;
        for(int i=1;i<=m;i++)
        scanf("%d %d",&a,&b),color[a][b]=grey;
        make_edge();
        //print();
        for(int i=1;i<=num_black;i++)
        {
            memset(used,0,sizeof(used));
            if(dfs(Black[i]))sum++;
            //cout<<Black[i]<<endl;
        }
        cout<<sum<<endl;
    }
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define grey 2
    #define black 1
    #define white 0
    int sum,n,m,Map[105][105],color[105][105],num_white,num_black,White[105],Black[10005],used[10005],match[10005];
    bool dfs(int u){
          int t,i;
          for (int v=1;v<=num_white;v++)
          {
                  i=White[v];
                  if (used[i]==0 && Map[u][i])
                  {
                              
                            used[i]=1;
                            t=match[i];
                            match[i]=u;
                            if (t==0 || dfs(t)) return 1;
                            match[i]=t;
                 }
                 
              }
          return 0;
    }
    void make_way(int u,int v)
    {
        Map[u][v]=1;
    }
    int make_num(int a,int b)
    {
        return ((n)*(a-1)+b);
    }
    void make_edge()
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            if(color[i][j]!=grey)
            {
                if(color[i][j]==white)
                {
                    White[++num_white]=make_num(i,j);
                }else Black[++num_black]=make_num(i,j);
                if(i>1&&color[i-1][j]!=grey) make_way(make_num(i,j),make_num(i-1,j));
                if(j>1&&color[i][j-1]!=grey) make_way(make_num(i,j),make_num(i,j-1));
                if(i<n&&color[i+1][j]!=grey) make_way(make_num(i,j),make_num(i+1,j));
                if(j<m&&color[i][j+1]!=grey) make_way(make_num(i,j),make_num(i,j+1));
            }
    }
    void draw(int n)
    {
        for(int i=1;i<=n;i++)
        {
            if(i%2) color[i][1]=black;else color[i][1]=white;  
            for(int j=2;j<=n;j++)
            {
                color[i][j]=1^color[i][j-1];
            }
        }
    }
    void print()
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            cout<<color[i][j];
            cout<<endl;
        }
    }
    int main()
    {
        scanf("%d %d",&n,&m);
        draw(n);
        int a,b;
        for(int i=1;i<=m;i++)
        scanf("%d %d",&a,&b),color[a][b]=grey;
        make_edge();
        //print();
        for(int i=1;i<=num_black;i++)
        {
            memset(used,0,sizeof(used));
            if(dfs(Black[i]))sum++;
            //cout<<Black[i]<<endl;
        }
        cout<<sum<<endl;
    }
  • 相关阅读:
    storyboard文件的认识
    设置程序启动时加载的storyboard
    IBAction和IBOutlet
    listview
    JDK下载地址
    [置顶] Docker学习总结(2)——Docker实战之入门以及Dockerfile(二)
    [置顶] Docker学习总结(1)——Docker实战之入门以及Dockerfile(一)
    [置顶] Docker学习总结(1)——Docker实战之入门以及Dockerfile(一)
    XML学习总结(2)——XML简单介绍
    XML学习总结(2)——XML简单介绍
  • 原文地址:https://www.cnblogs.com/dancer16/p/7208578.html
Copyright © 2020-2023  润新知