ZOJ Monthly, July 2011 - B Cake Robbery
http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=4366
(题意大概就是给出一些在凸多边形内部不相交的切割,求出边数最大的多边形的边数)
比赛的后半段时间差不多是我在搞这道题,搞了个错误的算法,一直WA到最后。
由于watashi神没有给出月赛的报告! scorpio牛说出一个很飘逸的叫“括号序列”
的算法。
大概步骤:
(1)对一个切割 i,j (i<j) ,i的出度加1,j的入度加1
(2)从小到大,找第一个出度不为0的开始点st。
(3)从st开始顺时针扫描。
顺时针压每条原始边。(这里的压边用压0表示)
遇到出度不为0的,压左括号和边。(说明这个点可能是多边形的一个顶点)
遇到入度不为0的,压右括号和边。(说明这个点可能是多边形的一个顶点)
(4)再次扫描到st点,结束。
#include <iostream> #include <cstdio> #include <algorithm> #include <string.h> #include <stack> #include <cmath> #include <vector> using namespace std; struct node { int r; int c; }a[10005]; int main() { int N,M,l,r; while(scanf("%d %d",&N,&M)!=EOF) { for(int i=1; i<=N; i++) a[i].r=0,a[i].c=0; for(int i=1; i<=M; i++) { scanf("%d %d",&l,&r); if(l>r) swap(l,r); a[l].c+=1; a[r].r+=1; } if(M==0) { printf("%d\n",N); continue; } int st=0; for(int i=1; i<=N; i++) { if(a[i].c==0) continue; st = i; break; } stack<int>s; while(s.size()>0) s.pop(); while(a[st].c>0) { s.push(st); s.push(0); a[st].c-=1; } int pur = st; int ans = 0; int cnt = 0; while(1) { pur = pur%N+1; s.push(0); //压原始边(边缘) if(pur == st) break; while(a[pur].r>0) { a[pur].r-=1; cnt=0; while(s.size()>0 && s.top()==0) { cnt+=1; s.pop(); } ans = max(cnt,ans); s.pop(); if(s.size()==0) { s.push(st); //栈空,还没结束,继续压左括号和边 s.push(0); } else s.push(0); //压边(替换消掉的多边形) } while(a[pur].c>0) { a[pur].c-=1; s.push(pur); s.push(0); } } cnt = 0; while(s.size()>0 && s.top()==0) { cnt+=1; s.pop(); } ans = max(ans,cnt); printf("%d\n",ans); } return 0; }