1 / 37

习题选讲

习题选讲. 搜索. 搜索. 1152 1153 马周游 Queens, Knights and Pawns 1024 Magic Island 1050 Numbers & Letters 1006 Team Rankings 1150 1151 1515 魔板. 题目大意 : 一个有限大小的棋盘上有一只马,马只能按日字方式走,如图所示。 给出初始时马的位置,找出一条马移动的路线,经过所有格子各一次。. 1152 1153 马周游. 1152 1153 马周游. 解题思路: 枚举马能走的所有路径,直至找到一条完成周游的路径; 递归,回溯。.

leanne
Download Presentation

习题选讲

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 习题选讲 搜索

  2. 搜索 • 1152 1153 马周游 • Queens, Knights and Pawns • 1024 Magic Island • 1050 Numbers & Letters • 1006 Team Rankings • 1150 1151 1515 魔板

  3. 题目大意: 一个有限大小的棋盘上有一只马,马只能按日字方式走,如图所示。 给出初始时马的位置,找出一条马移动的路线,经过所有格子各一次。 1152 1153 马周游

  4. 1152 1153 马周游 • 解题思路: • 枚举马能走的所有路径,直至找到一条完成周游的路径; • 递归,回溯。

  5. 1152 1153 马周游 • bool solve(int x, int y, int lev) { • route[lev] = x * N + y; • if (lev == M * N - 1) {print_route();return true; } • visited[x][y] = true; • grid grids[8]; • int n=get_grid(grids,x,y); • for (i=0; i<n; i++) • if (solve(grids[i].x, grids[i].y, lev+1)) • return true; • visited[x][y] = false; • return false; • }

  6. 1152 1153 马周游 • int get_grid(grid grids[], int x,int y) { • int n=0; • for (int i=0; i<8; i++) { • int xx = x + direction[i][0]; • int yy = y + direction[i][1]; • if (xx>=0&&yy>=0&&xx<M&&yy<N&&!visited[xx][yy]) { • grids[n].x = xx; • grids[n].y = yy; • n++; • } • } • return n; • }

  7. 1152 1153 马周游 • 以上程序速度过慢。 • 优化:改变搜索顺序。 • 先搜索可行格较少的格子。 • 其他顺序。 • 修改get_grid()函数。

  8. 1152 1153 马周游 • int get_grid(grid grids[], int x,int y) { • int n=0; • for (int i=0; i<8; i++) { • int xx = x + direction[i][0] • int yy = y + direction[i][1]; • if (xx>=0&&yy>=0&&xx<M&&yy<N&&!visited[xx][yy]) { • grids[n].x = xx; grids[n].y = yy; • grids[n].count = get_count(xx, yy); • n++; • } • } • sort(grids,grids+n); • return n; • }

  9. 1152 1153 马周游 • bool operator < (const grid &a, const grid &b) { • return a.count < b.count; • } • int get_count(int x, int y) { • int i, xx, yy, count = 0; • for (i=0; i<8; i++) { • xx = x + direction[i][0]; • yy = y + direction[i][1]; • if (xx>=0&&yy>=0&&xx<M&&yy<N&&!visited[xx][yy]) • count++; • } • return count; • }

  10. 不推荐! 1152 简单的马周游问题 const • 隐藏算法: • 5*6规模比较小 • 仅30种输入 • 每种的输出仅30个整数 • 完全可以使用const大法 • 先在本机跑出所有结果,然后O(1)输出

  11. 1172 Queens, Knights and Pawns • 题目大意: • 给出棋盘大小,给出每个后、马和兵的位置,求棋盘上有多个个没被占领的格子不会受到后也不会受到马的攻击。 • 棋盘大小最多为1000*1000,每种棋子最多100个。

  12. 1172 Queens, Knights and Pawns • 解题思路: • 用二维数组表示一个棋盘,标记每个棋子的位置,再标记每个棋子能攻击的位置,最后计算有多少个位置不会被攻击。

  13. 1172 Queens, Knights and Pawns • enum grid_state {empty,occupied,attacked}; • grid_state grid[1001][1001]; • int cal(vector<point> q, vector<point> k, vector<point> p) • { • memset(grid,0,sizeof(grid)); • occupy(q); occupy(k); occupy(p); • attackQ(q); attackK(k); • int s=0; • for (int i=1;i<=row;i++) • for (int j<=col;j++) • if (grid[i][j]==empty) • s++; • return s; • }

  14. 1172 Queens, Knights and Pawns • bool in_board_and_unoccupied(point p) { • if (p.x>=1&&p.x<=row) • if (p.y>=1&&p.y<=col) • return grid[p.x][p.y]!=occupied; • return false; • } • void occupy(vector<point> v) { • for (int i=0;i<v.size();i++) • grid[v[i].x][v[i].y]]=occupied; • }

  15. 1172 Queens, Knights and Pawns • int dQ[8][2]={{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}}; • void attackQ(vector<point> q) { • for (int i=0;i<q.size();i++) • for (int dir=0;dir<8;dir++) { • point temp(q[i].x+dQ[dir][0],q[i].y+dQ[dir][1]); • while (in_board_and_unoccupied(temp) { • grid[temp.x][temp.y]=attacked; • temp=point(temp.x+dQ[dir][0],temp.y+dQ[dir][1]; • } • } • }

  16. 1172 Queens, Knights and Pawns • int dK[8][2]={{1,2},{1,-2},{2,-1},{-2,-1},{-1,-2},{-1,2},{-2,1},{2,1}}; • void attackK(vector<point> k) { • for (int i=0;i<k.size();i++) • for (int dir=0;dir<8;dir++) { • point temp(k[i].x+dK[dir][0],k[i].y+dK[dir][1]); • if (in_board_and_unoccupied(temp) • grid[temp.x][temp.y]=attacked; • } • }

  17. 1024 Magic Island • 题目大意: • 给出一个有N个节点的树,从结点K开始出发,不重复经过任意一条边,求最远可以走的路程。

  18. 1024 Magic Island • 解题思路: • 树的性质:两个节点不经过重复边的路径有且只有一条。 • 从起点开始BFS或DFS,求出到所有节点的不经过重复边的路径长度,取其中的最大值即为答案。 struct node { int n; //顶点编号 int l; //起始点到该点的最大长度 }; vector<node> edge[N]; void dfs(intcur,intp,intl) { if (l>ans) ans=l; for (inti=0;i<edge[cur].length();i++) if (edge[cur][i].n!=p) dfs(edge[cur][i].n,cur,l+edge[cur][i].l); }

  19. 1050 Numbers & Letters • 题目大意 • 给5个整数,使用+, -, *, / 四种运算,可任意安排顺序和加括号,求一个不超过某给定值的最优解 • 解题思路 • Dfs(S) //S为操作数的集合 • 从S中任取两个数a, b进行运算得c • dfs(S-{a,b}+{c}) • 复杂度:C(5,2)*4*C(4,2)*4*C(3,2)*4*C(2,2)*4 = 46080

  20. 1050 Numbers & Letters void dfs(int a[], int n) { if (n==1) return; intb[5],m=0; for(inti=0;i<n;i++) for(intj=i+i;j<n;j++) { for(intk=0;k<n;k++) if (k!=i && k!=j) b[m++]=a[k]; update_answer(b[m]=a[i]+a[j]); dfs(b,m+1); update_answer(b[m]=a[i]-a[j]); dfs(b,m+1); update_answer(b[m]=a[j]-a[i]); dfs(b,m+1); update_answer(b[m]=a[i]*a[j]); dfs(b,m+1); if (a[j]!=0 && a[i]%a[j]==0) {update_answer(b[m]=a[i]/a[j]); dfs(b,m+1); } if (a[i]!=0 && a[j]%a[i]==0) {update_answer(b[m]=a[j]/a[i]); dfs(b,m+1); } } }

  21. 1006 Team Rankings • 题目大意: • 对于两个排列p, q,定义 distance( p, q )为在p, q中出现的相对次序不同的元素的对数。相当于以p为基准,求q的逆序数。 • 给出n个5元排列,构造一个排列,使得该排列对n个排列的distance之和最小。 • n<=100

  22. 1006 Team Rankings • 解题思路: • 枚举所有5元排列,与n个排列一一比较5个元素之间顺序并累加; • 枚举方法可用递归。 • 求逆序数的算法 • 平方级枚举 n^2 • 规模较大时可采用归并排序 nlogn

  23. 1006 Team Rankings void dfs(char rank[],intlev) { if (lev==5) { rank[5]='\0'; cal(rank); return; } for (char c='A';c<='E';c++) if (!used[c]) { rank[lev]=c; used[c]=true; dfs(rank,lev+1); used[c]=false; } }

  24. 1006 Team Rankings void cal(char rank[]) { int count=0; for (inti=0;i<n;i++) count+=distance(ranks[i],rank); if (count<ans_count) { ans_count=count; strcpy(ans,rank); } }

  25. 1006 Team Rankings int distance(char a[],char b[]) { intcnt=0; for (inti=0;i<5;i++) { posa[a[i]]=i; posb[b[i]]=i; } for (char c1='A';c1<='E';c1++) for (char c2=c1+1;c2<='E';c2++) if ((posa[c1]-posa[c2])*(posb[c1]-posb[c2])<0) cnt++; return cnt; }

  26. Tips What is求逆序数的快速算法? 归并排序的原理 What is nlogn? 通常出现的算法复杂度级别 O(mn),O(n!),O(nm),O(n),O(logn),O(1) 当n>10000时,至少要O(nlogn)

  27. 115011511515魔板 • 题目大意 • 魔板是2行4列的方格,八格分别标为1-8 • 初始状态为1 2 3 4 8 7 6 5 • 有三种操作: • 上下两行互换 1 2 3 4 8 7 6 5

  28. 115011511515魔板 • 题目大意 • 魔板是2行4列的方格,八格分别标为1-8 • 初始状态为1 2 3 4 8 7 6 5 • 有三种操作: • 上下两行互换 • 每行循环右移一格 1 2 3 4 8 7 6 5

  29. 115011511515魔板 • 题目大意 • 魔板是2行4列的方格,八格分别标为1-8 • 初始状态为1 2 3 4 8 7 6 5 • 有三种操作: • 上下两行互换 • 每行循环右移一格 • 中间四块顺时针转一格 1 2 3 4 8 7 6 5

  30. 115011511515魔板 • 题目大意 • 魔板是2行4列的方格,八格分别标为1-8 • 初始状态为1 2 3 4 8 7 6 5 • 有三种操作: • 上下两行互换 • 每行循环右移一格 • 中间四块顺时针转一格 • 给定一个终止状态,求最小操作数及方案 1 4 3 2 1 3 8 4 8 5 2 7 6 7 5 6

  31. 115011511515魔板 • 解题思路 • 对模板进行状态搜索 • 由一种状态可以转移到另外三种状态,搜索树为一棵三叉树 • 在这棵三叉树上搜索,目的是求出最优解

  32. 115011511515魔板 效果: 加优化后勉强可过1150 很傻很天真 评价: • 算法一:盲目DFS • 对这棵三叉树进行DFS • 若想求得最优解,需要遍历整棵树 • 需要进行重复扩展 • 优化:若已找到一个可行解,可剪去大于等于这个深度的所有子树

  33. 115011511515魔板 效果: 轻松切掉1150,但过不了1151 很慢很暴力 评价: • 算法二:BFS • 对这棵三叉树进行BFS • 第一个可行解即是最优解

  34. 115011511515魔板 效果: 轻松切掉以上三题 很快很易写 评价: • 算法三:DFS/BFS + 判重 • 可将一个魔板的状态编码,用8!以内的整数表示一个状态 • 可用8!的数组判重。每经过一个节点,把它放进已搜索列表中,每遇到一个节点,如果在已搜索列表存在,则不再扩展该节点。 • 不管DFS还是BFS,最多搜8!=40320个状态

  35. 1150 1151 1515 魔板 • state q[40320]; • void update(state new_state,int &head,int &tail, char opt) { • q[head]=new_state; • visit[hash(new_state)]=true; • parent[head]=tail; • op[head++]=opt; • }

  36. 1150 1151 1515 魔板 • void bfs(state start) { • int head=0,tail=0; • update(start,head,tail,'\0'); • while (tail<head) { • state new_state=A(q[tail]); • if (visit[hash(new_state)]==false) • update(new_state,head,tail,'A') • new_state=B(q[tail]); • if (visit[hash(new_state)]==false) • update(new_state,head,tail,'B') • state new_state=C(q[tail]); • if (visit[hash(new_state)]==false) • update(new_state,head,tail,'C') • tail++; • } • }

  37. 谢谢!

More Related