[NOIP2005] 篝火晚会

其实这个题目描述有点锅啊qwq

看了题解之后才明白过来原来编号没有要求连续qwq(但是题目中描述的那么规则到底是要怎样啊)

所以说这样题目就稍微简单了,要求的是初始环经过多少次变换成为符合条件的目标环。

那么首先我们需要先构建出来目标环。但是环不好处理,我们需要断环为链。但是断环为链显然是有两种情况,所以我们需要构建两个链。

eg.比如说样例的两种链情况:

1、2、4、3
1、3、2、1

然后有个结论就是:

遵循上述规律,使初始环变成期望环的代价是n-k(n是总数,k是在当前环和期望环中位置相同的数的个数)

构建完链之后按照上述规律来个check就可以了。

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
#define MAXN 60010
using namespace std;
int n,ans;
int l[MAXN],r[MAXN],sum[MAXN],done[MAXN],s[MAXN];
inline void quit()
{
    printf("-1\n");
    exit(0);
}
inline int check()
{
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=n;i++)
        sum[(s[i]-i+n)%n]++;
    int maxx=0;
    for(int i=0;i<=n;i++)
        maxx=max(maxx,sum[i]);
    return n-maxx;
}
inline int solve1()
{
    memset(done,0,sizeof(done));
    memset(s,0,sizeof(s));
    s[1]=1; done[s[1]]=1;
    s[2]=l[s[1]]; done[s[2]]=1;
    for(int i=2;i<n;i++)
    {
        if(l[s[i]]==s[i-1]) s[i+1]=r[s[i]],done[s[i+1]]=1;
        else if(r[s[i]]==s[i-1]) s[i+1]=l[s[i]],done[s[i+1]]=1;
    }
  	for(int i=1;i<=n;i++)
      if(!done[i])
          quit();
    return check();
}
inline int solve2()
{
    memset(done,0,sizeof(done));
    memset(s,0,sizeof(s));
    s[1]=1; done[s[1]]=1;
    s[2]=r[s[1]]; done[s[2]]=1;
    for(int i=2;i<n;i++)
    {
        if(l[s[i]]==s[i-1]) s[i+1]=r[s[i]],done[s[i+1]]=1;
        else if(r[s[i]]==s[i-1]) s[i+1]=l[s[i]],done[s[i+1]]=1;
    }
  	for(int i=1;i<=n;i++)
      if(!done[i])
          quit();
    return check();
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&l[i],&r[i]);
    printf("%d\n",min(solve1(),solve2()));
    return 0;
}
posted @ 2018-10-26 16:54  风浔凌  阅读(1004)  评论(0编辑  收藏  举报