SGU 190 解题手记
先把棋盘像国际象棋那样染成黑白相间,然后把需要挖掉的格子挖掉。将每个格子看作顶点,相邻的格子连一条边,这样就构成一个二分图了。在二分图上做匹配,复杂度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; } |
11 Responses
我用匈牙利写了,34s,你的多少s?
怎样才能看自己这道题的排名?
再问一下,hungary中O(nm)是指边*点 还是指左边的点*右边的点?
Reply
我是28ms,只有前20名可以看到。在problemset archive中点击accepted对应的链接。边*点。
Reply
大牛能否做下sgu141,我觉得自己做得是对的,但总是wa
Reply
可否告我邮箱,我把算法和程序发给你
Reply
我觉得二分图匹配也可以做到你n^2
Reply
你看sgu190能否这样做
在棋盘上找一个度为1的格子(意思是说只有一个格子和他相邻)
用一块domino把他覆盖,并把他和另一块被覆盖的格子删掉,更新度的信息,
如果没有度为1的,随便删一个1*2的格子
如果有一步发现有度为0的点说明no solution
Reply
这相当于对二分图做贪心匹配,用于求初始匹配可以大大提高Hungery算法的出解速度,但贪心匹配并不能保证求得最大匹配。反例如下:
G={{1,2,3,1',2',3'},{1-1',1-2',2-1',2-2',2-3',3-2',3-3'}}
贪心匹配可能求得{1-2',2-3'},这显然不是最大匹配。
Reply
弱弱的问一句,什么是hungery算法,二分图不是用匈牙利吗
Reply
出了点问题,上述反例在棋盘上构造不出来。可以在棋盘上构造出来的反例是:
G={{1,2,3,4,1',2',3',4'},{1-1',1-2',2-1',2-2',2-3',3-3',3-4',4-3',4-4'}}
贪心匹配求得{1-2',2-3',3-4'}。
Reply
我还是错了,你的算法不相当于贪心匹配。
Reply
我误把Hungary写成Hungery了。
Reply
Top Seven
Recent Comments
Categories
Blogroll
Login
Sponsor