[考试]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;
}

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

原文地址:https://www.cnblogs.com/jinkun113/p/4738012.html