【JZOJ 5284】【清华集训2017模拟】超级翻转

本文介绍了一种通过绕圈操作改变路径并寻找可行解的方法。该方法首先枚举一个终点,找出起点到终点的任意一条简单路径,然后在路径上选择位置绕圈以构造新的路径。通过这种方法,可以确保找到至少一个可行解。文章详细解释了如何逐行进行处理,并给出了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

这里写图片描述

Solution

先枚举一个终点,跑出起点到终点的任意一条简单路径,
我们发现,只要我们在这条路径上的一个位置绕一个圈,这条路径其实就改变了,
(比如:原来是(2,2)->(2,3),绕一圈是(2,2)->(2,3)->(1,3)->(1,2)->(2,2)->(2,3))
因为经过两次的边就等于没走嘛,所以上面这个例子相当于把原路径的这个位置搞凸起来,
又因为题目只要可行解,而这一肯定会有可行解的,

之后我们一行一行做,这一行全部清空,再往下走,
因为我们不能影响到上面,所以要把第i行清空,就必须在i+1行绕圈子(当然这样也会影响到i+2行),
发现,这样是唯一的,只有第一行是没法确认的,其他都可计算出,
有一种暴力就是枚举第一行选哪些绕圈子,

结论:第一行一定不选,
证明:以最上面那个图为例,
如果我们绕(1,2)这个格子,就相当于绕(2,1),(3,2),(4,3),(3,4),(2,3)这5个格子,这是等价的,
其他情况也差不多,这个例子显然是可以推广的,

所以直接做即可

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
const int N=20;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n,ans,x,y;
int a[N],b[N];
int er[20];
int s[N*N*N*N][2],s0;
void GOTO(int x,int y,int I,int J)
{
    fo(i,y,J-1)printf("R");
    fo(i,J,y-1)printf("L");
    fo(i,x,I-1)printf("D");
    fo(i,I,x-1)printf("U");
}
void GOTOb(int x,int y,int I,int J)
{
    fo(i,x,I-1)printf("D");
    fo(i,I,x-1)printf("U");
    fo(i,y,J-1)printf("R");
    fo(i,J,y-1)printf("L");
}
int main()
{
    freopen("turn.in","r",stdin);
    freopen("turn.out","w",stdout);
    int q,w,_;
    er[1]=1;fo(i,2,18)er[i]=er[i-1]<<1;
    read(_);
    while(_--)
    {
        read(n);
        fo(i,1,n)
        {
            a[i]=0;
            fo(j,1,n)if(read(q))a[i]+=er[j];
            b[i]=a[i];
        }
        read(x),read(y);
        bool OK=0;
        fo(I,1,n+1)if(!OK)fo(J,1,n+1)if(!OK)
        {
            fo(i,1,n)a[i]=b[i];
            fo(i,y,J-1)a[x-1]=a[x-1]^er[i],a[x]=a[x]^er[i];
            fo(i,J,y-1)a[x-1]=a[x-1]^er[i],a[x]=a[x]^er[i];
            fo(i,x,I-1)a[i]=a[i]^er[J]^er[J-1];
            fo(i,I,x-1)a[i]=a[i]^er[J]^er[J-1];
            s0=0;
            fo(i,1,n-1)
            {
                a[i]=a[i]&(er[n+1]-1);
                q=a[i];
                fo(j,1,n)if(q&er[j])s[++s0][0]=i+1,s[s0][1]=j;
                a[i]^=q;
                a[i+1]=a[i+1]^(q<<1)^(q>>1);
                a[i+2]^=q;
            }
            a[n]=a[n]&(er[n+1]-1);
            if(a[n]==0)
            {
                OK=1;
                s[0][0]=I,s[0][1]=J;
            }
        }
        if(OK)
        {
            fo(i,1,s0)
            {
                GOTO(x,y,s[i][0],s[i][1]);
                printf("RDLU");
                GOTOb(s[i][0],s[i][1],x,y);
            }
            GOTO(x,y,s[0][0],s[0][1]);
            printf("\n");
        }else printf("No Solution!\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值