• [考试]20150816


    1、前言

    同样是搜索题,感觉今天的鬼畜多了,还出现了一道标程都莫名其妙的题目。。。

    2、Maze 迷宫

    大概题意:在一个0-1矩阵中给出起始点和终点,求最短路径。(0为可走,1为不可走)

    总结:边界条件出了问题导致WA+RE了20分。我们可以把外围所有点设置为1(不可走),也可以在搜索时添加判断。还有一个很重要的问题,2000*2000的数据在读入时极有可能会超时,建议用读入优化。

    题解:最短路径推荐直接BFS。

    代码:

    -----------------------------------------------------------------------------------------------------

    #include<cstdio>
    #include<cstdlib>
    #define MAXN 2005
    #define INF 1<<30

    int max(int a,int b) { return (a>b)?a:b; }

    struct Queue
    {
      int x,y;
    };
    Queue q[MAXN*MAXN];

    const int vx[5]={0,-1,1,0,0};
    const int vy[5]={0,0,0,-1,1};

    int map[MAXN][MAXN],n,m,sx,sy,tx,ty;

    int check(int now)
    {
      if (q[now].x==tx && q[now].y==ty) printf("%d",map[q[now].x][q[now].y]-1),exit(0);
    }

    void BFS()
    {
      int head=1,tail=2; q[head].x=sx,q[head].y=sy,map[sx][sy]=1;
      while (head!=tail)
      {
        int nx=q[head].x,ny=q[head].y;
        for (int i=1;i<=4;i++)
          if (map[nx+vx[i]][ny+vy[i]]==0)
          {
            map[nx+vx[i]][ny+vy[i]]=map[nx][ny]+1;
            q[tail].x=nx+vx[i],q[tail].y=ny+vy[i];
            check(tail),tail++;
          }
        head++;
      }
    }

    int main()
    {
      freopen("maze.in","r",stdin);
      freopen("maze.out","w",stdout);
      scanf("%d %d",&n,&m);
      for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        {
          scanf("%d",&map[i][j]);
          map[i][j]=(!map[i][j])?0:-1;
        }  
      for (int i=1;i<=max(n,m);i++) map[0][i]=map[i][0]=map[n+1][i]=map[i][m+1]=-1;
      scanf("%d %d %d %d",&sx,&sy,&tx,&ty);
      BFS();
      printf("No Answer!");
      return 0;
    }

    -----------------------------------------------------------------------------------------------------

     

    3、Walk 走路

    大概题意:现有一个无限大的平面,给出n中行走方式,(dx,dy)表示可以从当前位置(x,y)走到(x+dx,y+dy),求出这些行走方式能否遍历到所有位置。

    总结:这是一道略让人无语的题目吧,方式多种多样,我写了一个根据读入数据最大值作为全遍历判断标准的贪心,但是只A了20分,WA了20分。看了标程,直接默认200*200作为判断依据;也有两个AC爷直接根据(-1,0),(1,0),(0,1),(0,-1)四个点来判断,默认最多走15步。这道题可以说并没有什么技巧可言,起初我以为又是要证明什么结论来确定范围。

    题解:BFS,具体的见总结。

    代码(from YMDragon):

    -----------------------------------------------------------------------------------------------------

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;

    int n,x[15],y[15],ans;

    bool check(int x,int y)
    {
      if ((x==1)&&(y==0)) ans|=1;
      if ((x==0)&&(y==1)) ans|=2;
      if ((x==-1)&&(y==0)) ans|=4;
      if ((x==0)&&(y=-1)) ans|=8;
      if (ans==15) return 1; return 0;
    }

    bool dfs(int j,int X,int Y,int st)
    {
      if (j>n) return check(X,Y);
      for (int i=0; i<=st; i++)
        if (dfs(j+1,X+i*x[j],Y+i*y[j],st-i)) return 1;
      return 0;
    }

    void work()
    {
      scanf("%d",&n);
      if (!n) exit(0);
      for (int i=1; i<=n; i++) scanf("%d %d",&x[i],&y[i]);
      ans=0;
      dfs(1,0,0,15);
      if (ans==15) printf("YES "); else printf("NO ");
    }

    int main()
    {
      freopen("walk.in","r",stdin);
      freopen("walk.out","w",stdout);
      while (1) work();
      return 0;
    }

    -----------------------------------------------------------------------------------------------------

    4、Chess 下棋

    大概题意:给出一个初始的4*4的O-X棋盘,当且仅当存在棋子四连时为胜利。X玩家想知道自己现在是否有必胜策略,以及最小字典序走法。

    总结:考场上完全没做出来,zzd说和SG游戏相关,其实核心依旧是搜索。

    题解:首先需要对于当前棋盘的状态进行压缩,大致思想在于,如果当前状态的后继状态存在某一方必胜的状态,那么该方为了胜利必将选择这条转移道路;由于我们需要X玩家的必胜策略,所以把O玩家的必胜看成X玩家的必败,进行DFS即可。

    代码(from z123z123d,有修改):

    -----------------------------------------------------------------------------------------------------

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #define MAXN 1000005
    #define MOD 1000007
    using namespace std;

    char x,ch[8][8];
    int n,m,s[20],go[MAXN],start,vis[MAXN];

    int check (int *a)
    {
      if (a[0]==2 && a[5]==2 && a[10]==2 && a[15]==2) return 0;
      if (a[0]==1 && a[5]==1 && a[10]==1 && a[15]==1) return -1;
      if (a[3]==2 && a[6]==2 && a[9]==2 && a[12]==2) return 0;
      if (a[3]==1 && a[6]==1 && a[9]==1 && a[12]==1) return -1;
      for (int i=0,f;i<16;i+=4)
      {
        f=0;
        for (int j=0;j<4;j++)
          if (!a[i+j] || (f && a[i+j]!=f)) { f=0; break; } else f=a[i+j];
        if (f) return (f==2)?0:-1;
      }
      for (int i=0,f;i<4;i++)
      {
        f=0;
        for (int j=0;j<16;j+=4)
          if (!a[i + j] || (f && a[i+j]!=f)) { f = 0; break; } else f=a[i+j];
        if (f) return (f==2)?0:-1;
      }
      return -2;
    }

    int work (int *a)
    {
      int ans=0;
      for (int i=15;i>=0;i--) ans=ans*3+a[i];
      return ans;
    }

    void rework (int *a,int &s1,int &s2,int num)
    {
      for (int i=0;i<16;i++) a[i]=num%3,num/=3,s1+=a[i]==1,s2+=a[i]==2;
    }

    void dfs(int now)
    {
      if (vis[now%MOD]) return; vis[now%MOD]=1;
      int nt[16]={0},s1=0,s2=0,t;
      rework(nt,s1,s2,now);
      t=check(nt);
      go[now%MOD]=(s1==s2)?-1:0;
      if (t!=-2) { go[now%MOD]=t; return; }
      for (int i=0;i<16;i++)
        if (!nt[i])
          if (s1<s2)
          {
            nt[i]=1,t=work(nt),dfs(t),nt[i]=0;
            if (go[t%MOD]==-1) { go[now%MOD]=-1; return; }
          }
          else
          {
            nt[i]=2,t=work(nt),dfs(t),nt[i]=0;
            if (go[t%MOD]>-1) { go[now%MOD]=i; return; }
          }
    }

    int main()
    {
      freopen("chess.in","r",stdin);
      freopen("chess.out","w",stdout);
      for (;;)
      {
        cin>>x;
        if (x=='$') break;
        for (int i=1;i<=4;i++) scanf("%s",ch[i]+1);
        for (int i=1;i<=4;i++)
          for (int j=1;j<=4;j++)
            s[4*(i-1)+j-1]=(ch[i][j]=='.')?0:(ch[i][j]=='o')?1:2;
        start=work(s);
        memset(vis,0,sizeof(vis));
        dfs(start);
        if (go[start%MOD]!=-1) printf("(%d,%d) ",go[start%MOD]/4,go[start%MOD]%4);
        else printf ("##### ");
      }
      return 0;
    }

    -----------------------------------------------------------------------------------------------------

    5、MC 最大团

    大概题意:求图的最大团,以及其个数。

    题解:待补充。

    代码:

    -----------------------------------------------------------------------------------------------------

    #include <cstdio>
    #define MAXN 55

    int map[MAXN][MAXN],n,m,ans,tot,max[MAXN],s[MAXN],x,y;

    void clear(int d) { for (int i=1;i<=n;i++) if (s[i]==d) s[i]--; }

    void dfs(int now,int nowAns)
    {
      int k=0;
      for (int i=now+1;i<=n;i++) if ((map[now][i]) && (s[i]==nowAns-1)) s[i]=nowAns,k++;
      if (k)
      {
        for (int i=now+1;i<=n;i++)
          if (s[i]==nowAns)
          {
            if ((nowAns+k<ans) || (nowAns+max[i]<ans)) break;
            dfs(i,nowAns+1),k--,s[i]--;
          }
        clear(nowAns);
      }
      else
      {
        if (nowAns>ans) ans=nowAns,tot=1;
        else if (nowAns==ans) tot++;
      }
    }

    int main()
    {
      freopen("mc.in","r",stdin);
      freopen("mc.out","w",stdout);
      scanf("%d %d",&n,&m);
      for (int i=1;i<=m;i++) scanf("%d %d",&x,&y),map[x][y]=1,map[y][x]=1;
      for (int i=n;i>=1;i--)
      {
        for (int j=i;j<=n;j++) s[j]=0;
        dfs(i,1); max[i]=ans;
      }
      printf("%d %d",ans,tot);
      return 0;
    }

    -----------------------------------------------------------------------------------------------------

  • 相关阅读:
    清北学堂模拟赛d5t6 cube
    清北学堂模拟赛d5t5 exLCS
    清北学堂模拟赛d5t4 套路
    清北学堂模拟赛d3t2 b
    清北学堂模拟赛d4t2 b
    Android(java)学习笔记196:ContentProvider使用之内容观察者01
    Android(java)学习笔记195:ContentProvider使用之添加数据到联系人(掌握)
    Android(java)学习笔记194:ContentProvider使用之获得系统联系人信息02(掌握)
    Android(java)学习笔记193:ContentProvider使用之获得系统联系人信息01
    Android(java)学习笔记192:ContentProvider使用之虚拟短信
  • 原文地址:https://www.cnblogs.com/jinkun113/p/4738012.html
Copyright © 2020-2023  润新知