SGU190 解题手记
  先把棋盘像国际象棋那样染成黑白相间,然后把需要挖掉的格子挖掉。将每个格子看作顶点,相邻的格子连一条边,这样就构成一个二分图了。在二分图上做匹配,复杂度O(N^4),有点悬。
  Submit 1: AC。事实证明,我的程序还是比较快的,排第13名(2008-2-21)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
 
int g[800][5]; //nb[i]: 0-pos of the ith black point, 1 2 3 4-pos of its neighbours in clockwise
int sy[800],xm[800],ym[800];
int n,p,m,black,white;
 
bool init()
{
    memset(xm,-1,sizeof(xm));
    memset(ym,-1,sizeof(ym));
    memset(g,-1,sizeof(g));
    scanf("%d%d",&n,&p);
    black=m=(n*n>>1)+(n&1); white=n*n-black;
    for(int i=0;i<n;++i)
        for(int j=i&1;j<n;j+=2) 
        {
            int k=i*n+j>>1;
            g[k][0]=i*n+j;
            i && (g[k][1]=g[k][0]-n);
            j<n-1 && (g[k][2]=g[k][0]+1);
            i<n-1 && (g[k][3]=g[k][0]+n);
            j && (g[k][4]=g[k][0]-1);
        }
    for (int i=0;i<p;++i)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if ((x--&1)==(y--&1))
        {
            black--;
            g[x*n+y>>1][0]=-1;
        }
        else
        {
            white--;
            int k=x*n+y;
            x && (g[k-n>>1][3]=-1);
            y<n-1 && (g[k+1>>1][4]=-1);
            x<n-1 && (g[k+n>>1][1]=-1);
            y && (g[k-1>>1][2]=-1);
        }
    }
    return black==white;
}
 
bool _path(int u)
{
    for(int v=1;v<5;v++) if(g[u][v]>=0 && !sy[g[u][v]>>1])
    {
        sy[g[u][v]>>1]=1;
        if(ym[g[u][v]>>1]==-1 || _path(ym[g[u][v]>>1])) { xm[u]=g[u][v]; ym[g[u][v]>>1]=u; return 1; }
    }
    return  0;
}
 
bool tenshi()
{
    int i;
    for(i=0;i<m;i++) if(g[i][0]>=0 && xm[i]==-1)
    {
        memset(sy,0,sizeof(sy));
        if(!_path(i)) return false;
    }
    return true;
}
 
int main()
{
    if (init() && tenshi())
    {
        printf("Yes\n");
        int h(0),v(0);
        for (int i=0;i<m;i++) if (xm[i]>=0)
            if (abs(xm[i]-g[i][0])==1) v++;
            else h++;
        printf("%d\n",h);
        for (int i=0;i<m;i++) if (abs(xm[i]-g[i][0])>1)
        {
            int k=min(xm[i],g[i][0]);
            printf("%d %d\n",k/n+1,k%n+1);
        }
        printf("%d\n",v);
        for (int i=0;i<m;i++) if (abs(xm[i]-g[i][0])==1)
        {
            int k=min(xm[i],g[i][0]);
            printf("%d %d\n",k/n+1,k%n+1);
        }
    }
    else printf("No\n");
    return 0;
}