首页 > 代码库 > 棋盘问题总结

棋盘问题总结

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

先看下面这道题

问题 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 0int 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;}
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>using namespace std;#define grey 2#define black 1#define white 0int 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;}

 

棋盘问题总结