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;
}