搜索专题题解

题目链接:

  codeforces 277A - Learning Languages

题目描述:

  一个团体有n个人,每个人都掌握了一些语言,每个人学一门语言有1个花费,两个人之间可以通过其他人的翻译,问最少花费多少使得这个团体的任意两个人都可以交流?

解题思路:

  可以bfs,dfs求连通块,也可以用并查集求集合数目。(PS:唯一要注意的是当每一个人都是只会0种语言,辣么每个人是不是都要学习语言,特判一下就好辣)

 搜索专题,先贴dfs代码咯~

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 205;
 4 struct Edge//邻接表建图,dfs求连通块数目
 5 {
 6     int to, next;
 7 };
 8 
 9 Edge edge[maxn*maxn];
10 int head[maxn], vis[maxn], tot;
11 
12 void Add (int from, int to)
13 {
14     edge[tot].to = to;
15     edge[tot].next = head[from];
16     head[from] = tot ++;
17 }
18 void dfs (int x)
19 {
20     vis[x] = 1;
21     for (int i=head[x]; i!=-1; i=edge[i].next)
22         if (!vis[edge[i].to])
23             dfs (edge[i].to);
24 }
25 
26 int main ()
27 {
28     int n, m;
29     while (scanf ("%d %d", &n, &m) != EOF)
30     {
31         int k, num, sum = 0;
32         tot = 0;
33         memset (head, -1, sizeof(head));
34         memset (edge, 0, sizeof(edge));
35         memset (vis, 0, sizeof(vis));
36         for (int i=0; i<n; i++)
37         {
38             scanf ("%d", &k);
39             sum += k;
40             while (k --)
41             {
42                 scanf ("%d", &num);
43                 Add (i, num+n-1);
44                 Add (num+n-1, i);
45             }
46         }
47         num = 0;
48         for (int i=0; i<n; i++)
49             if (!vis[i])
50             {
51                 dfs(i);
52                 num ++;
53             }
54         if (sum)
55             num --;
56         printf ("%d
", num);
57     }
58     return 0;
59 }
View Code

再贴一个并查集代码

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 205;
 4 int father[maxn], n, m;
 5 
 6 void init ()
 7 {
 8     for (int i=0; i<maxn; i++)
 9         father[i] = i;
10 }
11 int find (int x)
12 {
13     if (father[x] != x)
14         father[x] = find (father[x]);
15     return father[x];
16 }
17 int main ()
18 {
19     while (scanf ("%d %d", &n, &m) != EOF)
20     {
21         init ();
22         int k, x, ans = 0;
23         for (int i=1; i<=n; i++)
24         {
25             scanf ("%d", &k);
26             if (k)
27                 ans = -1;
28             while (k --)
29             {
30                 scanf ("%d", &x);
31                 int pi = find(i);
32                 int px = find(x+n);
33                 if (pi != px)
34                     father[px] = father[pi];
35             }
36         }
37         for (int i=1; i<=n; i++)
38             if (father[i] == i)
39             ans ++;
40         printf ("%d
", ans);
41     }
42     return 0;
43 }
View Code

 —————————————————————————————————————我是华丽的分割线——————————————————————————————————

题目链接:

  codeforce 520B - Two Buttons

题目描述:

  有n,m两个数,现有两种操作:

    1:n可以*2;2:n可以减1。问最少操作多少次可以使n==m?

解题思路:

  这次是最优解,又是搜索专题,肯定是bfs咯,tle的估计就是vis数组出问题咯,还有要注意n,m的范围哟!

还是先贴bfs代码

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 10005;
 4 struct node
 5 {
 6     int x, step;
 7 };
 8 int bfs (int n, int m)
 9 {
10     node p, q;
11     queue <node> Q;
12     int vis[maxn];
13     memset (vis, 0, sizeof(vis));
14     vis[n] = 1;
15     p.x = n;
16     p.step = 0;
17     Q.push (p);
18     while (!Q.empty())
19     {
20         p = Q.front();
21         Q.pop();
22         if (p.x == m)
23             return p.step;
24         q.step = p.step + 1;
25         int x = p.x - 1;
26         int y = p.x * 2;
27         if (x > 0 && !vis[x])
28         {
29             q.x = x;
30             Q.push (q);
31             vis[x] = 1;
32         }
33         if (p.x<m && y<maxn && !vis[y])
34         {
35             q.x = y;
36             Q.push (q);
37             vis[y] = 1;
38         }
39     }
40 }
41 int main ()
42 {
43     int n, m;
44     while (scanf ("%d %d", &n, &m) != EOF)
45         printf ("%d
", bfs(n, m));
46     return 0;
47 }
View Code

再贴一个代码,这个代码简单易懂

 1 /*这个要进行逆向思维
 2   这时候要考虑把m-->n
 3   两种操作就变成了m/2与m+1
 4   当m>n的时候只能进行+1操作
 5   当m<n的时候只能进行/2操作(要讨论m的奇偶性)
 6   循环操作,m==n的时候就一切ok啦
 7 */
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 const int maxn = 10005;
11 int main ()
12 {
13     int n, m, ans;
14     while (scanf ("%d %d", &n, &m) != EOF)
15     {
16         ans = 0;
17         while (true)
18         {
19             if (m <= n)
20             {
21                 ans += n - m;
22                 break;
23             }
24             if (m%2)
25             {
26                 m ++;
27                 ans ++;
28             }
29             m /= 2;
30             ans ++;
31         }
32         printf ("%d
", ans);
33     }
34     return 0;
35 }
View Code

这两个题目都可以用其他方法做,完美的避开了搜索,不知道会不会对小学弟(美)们造成误导哦,还是声明一下搜索很重要的,搜索很重要的,搜索很重要的(重要的事情说三遍)。是很多其他算法的基础。

————————————————————————————————————我是邪魅温柔的分割线——————————————————————————————

题目链接:

  Codeforces 445B - DZY Loves Chemistry

题目描述:

  n种试剂,m种反应(反应发生在两种试剂之间),DZY想要把这n种试剂混合,DZY依次向试管中加入试剂,刚开始试管的危险系数为1,如果当前所需要加入的试剂能与试管中的某种试剂反应,则试管的危险系数乘二,现在为了安全起见,问试管最高的危险系数是多少?

解题思路:

  很裸地并查集嘛!因为最终的状态肯定是所有的试剂都在试管里面,只需要知道每个集合里面元素个数就OK啦!!

 1 #include <queue>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 using namespace std;
 7 typedef __int64 LL;
 8 const int maxn = 100;
 9 int father[maxn];
10 void init ()
11 {
12     for (int i=0; i<maxn; i++)
13         father[i] = i;
14 }
15 int Find(int x)
16 {
17     if (x != father[x])
18         father[x] = Find(father[x]);
19     return father[x];
20 }
21 int main ()
22 {
23     int n, m;
24     while (scanf ("%d %d", &n, &m) != EOF)
25     {
26         init ();
27         LL ans = 1;
28         while (m --)
29         {
30             int x, y;
31             scanf ("%d %d", &x, &y);
32             int px = Find (x);
33             int py = Find (y);
34             if (px != py)
35             {
36                 father[px] = py;
37                 ans *= 2;
38             }
39         }
40         printf ("%I64d
", ans);
41     }
42     return 0;
43 }
本文为博主原创文章,未经博主允许不得转载。
原文地址:https://www.cnblogs.com/alihenaixiao/p/4653579.html