POJ基础搜索题练习(计划6-8题)

Problems

POJ2531 - Network Saboteur

POJ3009 - Curling 2.0

POJ3414 - Pots

 

Solutions

POJ2531 - Network Saboteur

题目大意:N个节点的完全图(2<=N<=20),以邻接矩阵C的形式给出节点两两之间连边的权值。现在需要将这些节点分为A、B两个子集,使得Ci(iAjB)最大。

考虑到节点总数不超过20,所以直接枚举子集的复杂度O(2^N)是可以接受的,要更进一步节省时间的话,一来由于对称性可以把节点0固定在子集A内,二来在枚举子集A的时候一旦新加入一个元素就更新总和,不必到叶子节点再计算。

 1 //  Problem: poj2531 - Network Saboteur
 2 //  Category: Depth first search
 3 //  Author: Niwatori
 4 //  Date: 2016/07/19
 5 
 6 #include <iostream>
 7 using namespace std;
 8 #define MAX(a,b) ((a)>(b)?(a):(b))
 9 
10 int m[25][25], set1[25] = {0}, set2[25] = {0};
11 int cnt1 = 0, cnt2 = 0, ans = 0;
12 
13 void dfs(int lev, int n, int tot)
14 {
15     if (lev == n)
16         {ans = MAX(ans, tot); return;}
17 
18     int tot1 = tot, tot2 = tot;
19     set1[cnt1++] = lev;
20     for (int i = 0; i < cnt2; ++i)
21         tot1 += m[lev][set2[i]];
22     dfs(lev + 1, n, tot1); --cnt1;
23 
24     set2[cnt2++] = lev;
25     for (int i = 0; i < cnt1; ++i)
26         tot2 += m[lev][set1[i]];
27     dfs(lev + 1, n, tot2); --cnt2;
28 }
29 
30 int main()
31 {
32     int n; cin >> n;
33     for (int i = 0; i < n; ++i)
34         for (int j = 0; j < n; ++j)
35             cin >> m[i][j];
36     set1[cnt1++] = 0;   // Fix node 0
37     dfs(1, n, 0);
38     cout << ans << endl;
39     return 0;
40 }
View Code

 

POJ3009 - Curling 2.0

题目大意:在冰面上有一个小球,每次可以给小球指定一个运动方向,根据牛顿第一定律(雾)小球会一直沿着这个方向运动,直到碰到障碍物、终点或者出界,如果碰到障碍物那么障碍物会消失,如果出界则游戏失败。给定起点和终点,输出最少的运动次数(若超过10则输出-1),场地的长宽均不超过20。

图1:样例,S代表起点,G代表终点,阴影表示障碍物

图1:样例,S代表起点,G代表终点,阴影表示障碍物

图2:样例的运动轨迹以及最终的场地状态

首先这道题要求的是最少次数,第一反应应当是bfs,但是考虑到每次运动之后,场地上的状态都会发生变化,记录场地状态所需要的空间开销过大,因而考虑dfs遍历所有可能的轨迹,选出其中最优的,且题目中「次数不超过10」是一个很明显的剪枝提示。估计一下总状态数最多为4^10大约10^7,搜索过程中及时剪掉那些不可行的运动方向可以大大缩小搜索状态空间,就一不小心AC了。

 1 //  Problem: poj3009 - Curling 2.0
 2 //  Category: Depth first search
 3 //  Author: Niwatori
 4 //  Date: 2016/07/19
 5 
 6 #include <stdio.h>
 7 #define MIN(a,b) ((a)<(b)?(a):(b))
 8 
 9 int nrow, ncol, ans, m[25][25];
10 int dx[] = {1,0,-1,0}, dy[] = {0,1,0,-1};
11 
12 inline bool check(int x, int y)
13 {
14     if (x < 0 || x >= nrow || y < 0 || y >= ncol) return 0;
15     return m[x][y] != 1;
16 }
17 
18 void dfs(int lev, int x, int y)
19 {
20     if (lev > 10) return;           // Search terminated after 10 levels
21     for (int i = 0; i < 4; ++i)
22     {
23         int newx = x, newy = y, ok = 0;
24         while (check(newx + dx[i], newy + dy[i]))
25         {
26             newx += dx[i]; newy += dy[i];
27             if (m[newx][newy] == 3) // Reach the goal!
28                 {ans = MIN(lev, ans); ok = 1; break;}
29         }
30         
31         // Circumstances of skipping direction i:
32         // 1. Pass by the goal halfway; 2. Unfeasible direction; 3. Out of range
33         int tmpx = newx + dx[i], tmpy = newy + dy[i];
34         if (ok || (newx == x && newy == y)) continue;
35         if (tmpx < 0 || tmpx >= nrow || tmpy < 0 || tmpy >= ncol) continue;
36         
37         m[tmpx][tmpy] = 0;          // Blocks disappear
38         dfs(lev + 1, newx, newy);
39         m[tmpx][tmpy] = 1;          // Backtrace
40     }
41 }
42 
43 int main()
44 {
45     while (scanf("%d%d", &ncol, &nrow) == 2)
46     {
47         if (!nrow && !ncol) break;
48         int sr, sc;
49         for (int i = 0; i < nrow; ++i)
50             for (int j = 0; j < ncol; ++j)
51             {
52                 scanf("%d", &m[i][j]);
53                 if (m[i][j] == 2) {sr = i; sc = j;}
54             }
55         ans = 20;
56         dfs(1, sr, sc);
57         printf("%d\n", ans <= 10 ? ans : -1);
58     }
59     return 0;
60 }
View Code

 

POJ3414 - Pots

题目大意:有两个容器,容积分别为A升和B升(1<=A, B<=100),允许以下三种操作:装满一个容器、倒空一个容器,将一个容器倒入另一个,求最少需要几步可以在一个容器中得到C升水,并输出任意一种可行的操作方案。

直接应用bfs即可,分别以两个容器中的水量作为访问数组的两个维度来判重。至于输出方案,由于笔者懒,所以就直接把操作步骤用字符串存起来放在队列里了,最后把它还原成输出的样式就可以啦。

 1 //  Problem: poj3414 - Pots
 2 //  Category: Breadth first search
 3 //  Author: Niwatori
 4 //  Date: 2016/07/19
 5 
 6 #include <stdio.h>
 7 #include <queue>
 8 #include <string>
 9 #define MIN(a,b) ((a)<(b)?(a):(b))
10 #define MAX(a,b) ((a)>(b)?(a):(b))
11 using std::string;
12 using std::queue;
13 
14 struct node{
15     int c1, c2; string steps;
16     node(int c1_, int c2_, string s_):c1(c1_),c2(c2_),steps(s_){}
17 };
18 
19 int main()
20 {
21     int A, B, C, vis[105][105] = {0};
22     scanf("%d%d%d", &A, &B, &C);
23 
24     queue<node> q;
25     q.push(node(0, 0, ""));
26     vis[0][0] = 1;
27     while (!q.empty())
28     {
29         node now = q.front();
30         if (now.c1 == C || now.c2 == C) break; q.pop();
31 
32         // Fill
33         if (!vis[A][now.c2])
34         {
35             vis[A][now.c2] = 1;
36             q.push(node(A, now.c2, now.steps + "F1"));
37         }
38         if (!vis[now.c1][B])
39         {
40             vis[now.c1][B] = 1;
41             q.push(node(now.c1, B, now.steps + "F2"));
42         }
43 
44         // Drop
45         if (!vis[0][now.c2])
46         {
47             vis[0][now.c2] = 1;
48             q.push(node(0, now.c2, now.steps + "D1"));
49         }
50         if (!vis[now.c1][0])
51         {
52             vis[now.c1][0] = 1;
53             q.push(node(now.c1, 0, now.steps + "D2"));
54         }
55 
56         // Pour
57         int newc1 = MAX(now.c1 - (B - now.c2), 0);
58         int newc2 = MIN(now.c1 + now.c2, B);
59         if (!vis[newc1][newc2])
60         {
61             vis[newc1][newc2] = 1;
62             q.push(node(newc1, newc2, now.steps + "P1"));
63         }
64         newc1 = MIN(now.c1 + now.c2, A);
65         newc2 = MAX(now.c2 - (A - now.c1), 0);
66         if (!vis[newc1][newc2])
67         {
68             vis[newc1][newc2] = 1;
69             q.push(node(newc1, newc2, now.steps + "P2"));
70         }
71     }
72 
73     if (q.empty())
74         printf("impossible");
75     else
76     {
77         string s = q.front().steps;
78         printf("%d\n", s.length() / 2);
79         for (int i = 0; i < s.length(); i += 2)
80             switch (s[i])
81             {
82                 case 'F': printf("FILL(%d)\n", s[i + 1] - '0'); break;
83                 case 'D': printf("DROP(%d)\n", s[i + 1] - '0'); break;
84                 case 'P': printf("POUR(%d,%d)\n", s[i + 1] - '0', 3 - (s[i + 1] - '0'));
85             }
86     }
87     return 0;
88 }
View Code

 

 

转载于:https://www.cnblogs.com/niwatori1217/p/5692889.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值