CF512E Fox And Polygon

CF512E Fox And Polygon

分析题意,我们首先需要知道这样一个性质:图形的任意两种状态之间是可以相互转换的。
也就是说,没有哪种状态是初始状态不能变化到的;同理,也没有哪种状态是终止状态不能变化到的。
此外我们还可以发现,变化步骤是可以倒推的。
结合以上几点,就可以得到这道题的做法了。
首先我们需要找到一个中间状态,为了方便,我们将这个中间状态定为所有点联向$1$号点的情况。
然后我们分别求出由初始状态变化为中间状态,和由终止状态变化为中间状态的步骤。
这个找步骤的过程如下:
枚举每个点,在这个点的左右两边分别找到一个与$1$点相连的点。根据分法(划分为数个三角形)可知,这两个点必然相连。然后删去这两点间的这条对角线并存储步骤即可。
这里需要注意的是,新出现的对角线并不一定是$1$号点和当前枚举点的连线,所以要枚举找出这个同时与被删去对角线两端点相连的点。
再这样一次操作后,当前枚举点不一定就会与$1$号点相连,所以要循环直到$1$号点和当前点相连为止,再枚举下一个点。
用同样的方法找到由终止状态到中间状态的变化过程。注意存储的步骤是新出现对角线的两个端点
最后输出所有步骤即可,其中由终止状态变化到中间状态的步骤需要倒序输出。
(但是我现在还没证明步骤数必定在$20000$之内,所以记录步骤用vector会更好)

#include<bits/stdc++.h>
#define N 1010

using namespace std;

int n,cnt1,cnt2;
bool edge1[N][N],edge2[N][N];

struct node {
    int frm,to;
}op1[20010],op2[20010];

void Read() {
    scanf("%d",&n);
    for(int i=1;i<=n-3;i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        edge1[u][v]=1;
        edge1[v][u]=1;
    }
    for(int i=1;i<=n-3;i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        edge2[u][v]=1;
        edge2[v][u]=1;
    }
    return;
}

void Solve() {
    for(int i=1;i<=n;i++) {
        edge1[i][i%n+1]=1;
        edge1[i%n+1][i]=1;
        edge2[i][i%n+1]=1;
        edge2[i%n+1][i]=1;
    }

    for(int i=2;i<=n;i++) {
        while(!edge1[1][i]) {
            int su=i-1,sv,eu=0,ev; //su=i-1:i的上一个点必与1点相连 su-sv -> es-ev
            for(int j=i+1;j<=n;j++) {
                if(edge1[1][j]) {
                    sv=j;
                    break;
                }
            }
            for(int k=1;k<=n;k++) {
                if(edge1[su][k]&&edge1[sv][k]) {
                    if(eu==0) {
                        eu=k;
                    }
                    else {
                        ev=k;
                        break;
                    }
                }
            }
            edge1[su][sv]=0;
            edge1[sv][su]=0;
            edge1[eu][ev]=1;
            edge1[ev][eu]=1;
            op1[++cnt1]=(node){su,sv};
            //printf("op:%d %d %d %d i:%d\n",su,sv,eu,ev,i);
        }
    }
    for(int i=2;i<=n;i++) {
        while(!edge2[1][i]) {
            int su=i-1,sv,eu=0,ev; //su=i-1:i的上一个点必与1点相连 su-sv -> es-ev
            for(int j=i+1;j<=n;j++) {
                if(edge2[1][j]) {
                    sv=j;
                    break;
                }
            }
            for(int k=1;k<=n;k++) {
                if(edge2[su][k]&&edge2[sv][k]) {
                    if(eu==0) {
                        eu=k;
                    }
                    else {
                        ev=k;
                        break;
                    }
                }
            }
            edge2[su][sv]=0;
            edge2[sv][su]=0;
            edge2[eu][ev]=1;
            edge2[ev][eu]=1;
            op2[++cnt2]=(node){eu,ev};
            //printf("op:%d %d %d %d i:%d\n",su,sv,eu,ev,i);
        }
    }

    return;
}

void Print() {
    printf("%d\n",cnt1+cnt2);
    for(int i=1;i<=cnt1;i++) {
        printf("%d %d\n",op1[i].frm,op1[i].to);
    }
    for(int i=cnt2;i>=1;i--) {
        printf("%d %d\n",op2[i].frm,op2[i].to);
    }
    return;
}

int main()
{
    Read();
    Solve();
    Print();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/luoshui-tianyi/p/12194582.html