AYIT-2020 609暑假集训第一周周赛题题解

A - A计划

 题意:中文题很好理解;

思路:开个三维数组来存放地图,bfs板子,只是在"#"的地方要换下位置就可以了。

AC代码:

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
#define mod 1000000007
#define eps 1e-9
#define PI acos(-1.0)
#define mem(a,b) memset(a,b,sizeof(a))
char s[3][12][12];//三维数组存图
int n,m,k,a[10],t;
int book[12][12][12];//三维数组标记
int to[4][2]= {{1,0},{0,1},{-1,0},{0,-1}};//四个方向
struct node
{
    int w,x,y,step;
};
void bfs()
{
    queueq;
    node u,v;
    u.x=0,u.y=0;
    u.w=0,u.step=0;
    book[0][0][0]=1;
    q.push(u);
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        if(s[u.w][u.x][u.y]=='P'&&u.step<=k)//满足条件输出结果
    
            printf("YES\n");
            return;
        }
        for(int i=0; i<4; i++)
        {
            int dx=u.x+to[i][0];
            int dy=u.y+to[i][1];
            if(dx>=0&&dx=0&&dy

 

B - 非常可乐

 题意:中文题。

思路:当状态中的t,n,m任意两个为t/2时,说明存在最小要倒次数,直接模拟倒水的过程,一共六种情况,把每一种情况都考虑一遍,代码如下。

AC代码:

#include
#include
#include
using namespace std;
struct node
{
    int x,y,step,z;
};
int t,n,m;
int book[120][120][119];//标记三个瓶子的状态
void dfs()
{
    node v,u;
    queueq;
    u.x=0;
    u.y=0;
    u.step=0;
    u.z=t;
    book[t][0][0]=1;
    q.push(u);
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        v=u;
        if(u.z==t/2&&(u.x==t/2||u.y==t/2))//满足条件输出
        {
            printf("%d\n",u.step);
            return;
        }
        for(int i=0; i<6; i++)//一共六种情况,自己推导一下
        {
            if(i==0)//z-->x(表示z瓶的可乐倒入x瓶,同下)
            {
                if(u.z+u.x>=n)
                {
                    v.x=n;
                    v.z=u.z+u.x-n;
                }
                else
                {
                    v.x=u.z+u.x;
                    v.z=0;
                }
                v.y=u.y;
            }
            if(i==1)//z-->y
            {
                if(u.z+u.y>=m)
                {
                    v.z=u.z+u.y-m;
                    v.y=m;
                }
                else
                {
                    v.z=0;
                    v.y=u.y+u.z;
                }
                v.x=u.x;
            }
            if(i==2)//x-->y
            {
                if(u.x+u.y>=m)
                {
                    v.x=u.x+u.y-m;
                    v.y=m;
                }
                else
                {
                    v.x=0;
                    v.y=u.x+u.y;
                }
                v.z=u.z;
            }
            if(i==3)//y-->x
            {
                if(u.x+u.y>=n)
                {
                    v.x=n;
                    v.y=u.x+u.y-n;
                }
                else
                {
                    v.x=u.x+u.y;
                    v.y=0;
                }
                v.z=u.z;
            }
            if(i==4)//x-->z
            {
                v.z=u.z+u.x;
                v.x=0;
                v.y=u.y;
            }
            if(i==5)//y-->z
            {
                v.z=u.z+u.y;
                v.y=0;
                v.x=u.x;
            }
            if(book[v.z][v.x][v.y]==0)
            {
                book[v.z][v.x][v.y]=1;
                v.step=u.step+1;
                q.push(v);
            }
        }
    }
    printf("NO\n");
}
int main()
{
    while(~scanf("%d%d%d",&t,&n,&m)&&(t||n||m))
    {
        memset(book,0,sizeof(book));
        if(t%2==1)//进行特判,如果t不能被二整除直接输出NO
        {
            printf("NO\n");
            continue;
        }
        else
            dfs();
    }
    return 0;
}

C - 哈密顿绕行世界问题

 题意:这个一道简单的深搜题,并输出路径,把所有的情况都输出出来。

思路:直接用深搜板子写即可,注意细节我在代码中注释出来,不要被它的输出吓到了。

AC代码:

#include
#include
#include
using namespace std;
int s[21][3],d[21];
int n,book[30],l;
void dfs(int x,int y)
{
    if(y==20&&(s[x][0]==d[0]||s[x][1]==d[0]||s[x][2]==d[0]))//满足条件输出一种结果
    {
        printf("%d:  ",l++);//注意输出格式
        for(int i=0; i<20; i++)
        {
            printf("%d ",d[i]);
        }
        printf("%d",d[0]);
        printf("\n");
        return ;
    }
    for(int j=0; j<=2; j++)
    {
        if(book[s[x][j]]==0)
        {
            book[s[x][j]]=1;
            d[y]=s[x][j];//记录路径
            int t=s[x][j];
            dfs(t,y+1);
            book[s[x][j]]=0;//注意返回之后要取消标记
        }
    }
    return ;
}
int main()
{
    for(int i=1; i<=20; i++)
    {
        for(int j=0; j<=2; j++)
            scanf("%d",&s[i][j]);
        sort(s[i],s[i]+3);
    }
    while(~scanf("%d",&n)&&n!=0)
    {
        memset(book,0,sizeof(book));//注意标记数组清空
        book[n]=1;
        d[0]=n;
        l=1;
        dfs(n,1);
    }
    return 0;
}

D - The Center of Gravity

 题意:三角形的三个点的坐标,求出这个三角形的重心。

思路:超级简单的一道题,套用公式即可:

AC代码:

#include
#include
#include
using namespace std;
int main()
{
    int n;
    double x1,x2,x3,y1,y2,y3;
    while(~scanf("%d",&n)&&n)
    {
        while(n--)
        {
            scanf("%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&x3,&y3);
            double x=(x1+x2+x3)/3.0;
            double y=(y1+y2+y3)/3.0;
            printf("%.1f %.1f\n",x,y);
        }
    }
}

E - Eight

 题意:给一个状态让你变成给定状态12345678X,输出路径,如果不行输出unsolvable;注意:路径不唯一。

思路:把所有的情况都列出来,例1 2 3 4 5 6 7 x 8,只需将x向右移动一次,并记录这个路径。康托展开:详细介绍:https://blog.csdn.net/qq_38701476/article/details/81003290  大家也可以用map容器进行存路径,也是可以的。

康托展开的代码:

        for(int i=0; i<9; i++)
        {
            int ll=0;
            for(int j=i+1; j<9; j++)
                if(w[i]>w[j])
                    ll=ll+1;
            num=num+ll*jc[8-i];
        }

AC代码:

#include
#include
#include
#include
using namespace std;
struct node
{
    int h,x,y,z,b[5][5];//x横坐标,y纵坐标
};
int s[5][5],book[400000],jc[11];
char book1[400000];
int to[4][2]= {{1,0},{0,1},{-1,0},{0,-1}} ;//方向d,r,u,l;
void bfs()
{
    queueq;
    node u,v;
    u.h=9;
    u.x=2;
    u.y=2;
    u.z=0;
    for(int i=0; i<3; i++)
        for(int j=0; j<3; j++)
            u.b[i][j]=s[i][j];
    book[0]=0;
    q.push(u);
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        for(int i=0; i<4; i++)
        {
            v=u;
            int dx=u.x+to[i][0];
            int dy=u.y+to[i][1];
            if(dx>=0&&dx<3&&dy>=0&&dy<3)
            {
                v.h=u.b[dx][dy];
                v.x=dx;
                v.y=dy;
                int tt;//交换位置
                tt=u.b[dx][dy];
                v.b[dx][dy]=u.b[u.x][u.y];
                v.b[u.x][u.y]=tt;
                int kk[10];
                int o=0;
                for(int i=0; i<3; i++)
                    for(int j=0; j<3; j++)
                        kk[o++]=v.b[i][j];
                int sum=0;
                for(int i=0; i<9; i++)//康托展开
                {
                    int l=0;
                    for(int j=i+1; j<9; j++)
                        if(kk[i]>kk[j])
                            l=l+1;
                    sum=sum+l*jc[8-i];
                }
                v.z=sum;
                if(book[sum]==-1)//记录路径
                {
                    book[sum]=u.z;
                    if(i==0)
                        book1[sum]='u';
                    if(i==1)
                        book1[sum]='l';
                    if(i==2)
                        book1[sum]='d';
                    if(i==3)
                        book1[sum]='r';
                    q.push(v);
                }
            }
        }
    }
}
int main()
{
    int t=1;
    for(int i=0; i<3; i++)
        for(int j=0; j<3; j++)
            s[i][j]=t++;
    for(int i=0; i<400000; i++)
        book[i]=-1;
    jc[0]=0;
    jc[1]=1;
    for(int i=2; i<9; i++)//阶乘
        jc[i]=i*jc[i-1];
    bfs();
    char n[100],m[10];
    int w[10];
    while(gets(n))
    {
        int d=strlen(n),f=0;
        for(int i=0; iw[j])
                    ll=ll+1;
            num=num+ll*jc[8-i];
        }
        if(book[num]==-1)
            printf("unsolvable");
        else
            while(num!=0)
            {
                printf("%c",book1[num]);
                num=book[num];
            }
        printf("\n");
    }
    return 0;
}
//1 2 3 4 x 5 6 7 8  rdllurdrulldrr

F - Magic Cube

 题意:给出魔方六面,每一面标号如上,给出一种排列,你需要把它复原,求最少步数和步骤,不能超过5步。1表示顺时针,-1表示逆时针。

思路:用IDA*搜索,因为中心颜色确定,找出每个面与中心颜色不同的数量, 每次旋转最多改变12个, 当不同数量/12>深度时剪枝。

AC代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
#define mod 1000000007
#define mem(a,b) memset(a,b,sizeof(a))
#define PI acos(-1.0)
#define eps 1e-8
#define N 1000100
int n,m;
int flag,sum,res[10];
int row[6][8]=
{
    {0,1,2,3,5,6,7,8},{9,10,11,21,23,33,34,35},{12,13,14,24,26,36,37,38},
    {15,16,17,27,29,39,40,41},{18,19,20,30,32,42,43,44},{45,46,47,48,50,51,52,53}
};
int change[12][20]=
{
    {11,23,35,34,33,21,9,10,51,48,45,36,24,12,6,3,0,20,32,44},
    {9,10,11,23,35,34,33,21,36,24,12,6,3,0,20,32,44,51,48,45},
    {14,13,26,38,37,36,24,12,45,46,47,39,27,15,8,7,6,11,23,35},
    {12,24,13,14,26,38,37,36,39,27,15,8,7,6,11,23,35,45,46,47},
    {17,29,41,40,39,27,15,16,47,50,53,42,30,18,2,5,8,14,26,38},
    {15,16,17,29,41,40,39,27,42,30,18,2,5,8,14,26,38,47,50,53},
    {18,19,20,32,44,43,42,30,53,52,51,33,21,9,0,1,2,17,29,41},
    {42,30,18,19,20,32,44,43,33,21,9,0,1,2,17,29,41,53,52,51},
    {0,1,2,5,8,7,6,3,12,13,14,15,16,17,18,19,20,9,10,11},
    {6,3,0,1,2,5,8,7,15,16,17,18,19,20,9,10,11,12,13,14},
    {45,46,47,50,53,52,51,48,44,43,42,41,40,39,38,37,36,35,34,33},
    {51,48,45,46,47,50,53,52,41,40,39,38,37,36,35,34,33,44,43,42}
};
int cen[6]= {4,22,25,28,31,49};
char s[11],c[60],ct[60];
int lenn(char *tmp)
{
    int ans=0;
    for(int i=0; i<6; i++)
    {
        int t=0;
        for(int j=0; j<8; j++)
            if(tmp[row[i][j]]!=tmp[cen[i]])
                t++;
        ans=max(ans,t);
    }
    return (ans+2)/3;
}
void IDAstar(int step, char a[], int fa)
{
    int t=lenn(a);
    if(step+t>sum)
        return;
    if(!t)
    {
        flag=1;
        return;
    }
    char tmp[60];
    for(int i=0; i<12; i++)
    {
        if((fa^i)==1)
            continue;
        memcpy(tmp,a,60*sizeof(char));
        res[step]=i;
        for(int j=0; j<20; j++)
            tmp[change[i][j]] = a[change[i^1][j]];
        IDAstar(step+1,tmp,i);
        if(flag)
            return;
    }
}
int main()
{
    int i,j,k,kk,t,x,y,z;
    scanf("%d",&k);
    while(k--)
    {
        for(i=0; i<54; i++)
        {
            scanf("%s",s);
            c[i]=s[0];
        }
        flag=0;
        sum=lenn(c);
        while(sum<=5)
        {
            IDAstar(0,c,-1);
            if(flag)
            {
                printf("%d\n",sum);
                for(i=0; i

 

你可能感兴趣的:(大一训练题解)