思维专题(不定期更新)

Posted 萌萌的美男子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了思维专题(不定期更新)相关的知识,希望对你有一定的参考价值。

1、UVa 11100 - The Trip, 2007

  题意:给出若干大小不同的包裹,小的能够装在大的包裹里面。求最小的大包裹数,并且保证在所有的大包裹中,所含有的小包裹数目最小。

  思路:显然,相同大小的包只能放在不同的大包里,那么最小的大包数目就是相同大小的包的最大数目,记为k。之后,根据从小到大排序后,对于每个大包i可选取从i开始,间隔k个包的那些包裹作为该大包从里到外的各个包裹。

 

技术分享
 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 int dm[10005];
 5 int main()
 6 {
 7     int k = 1,n;
 8     while (cin >> n, n != 0)
 9     {
10         for (int i = 0; i < n; i++) cin >> dm[i];
11         sort(dm, dm + n);
12         int maxt = 1;
13         for (int i = 1, t = 1; i < n; i++)
14         {
15             if (dm[i] == dm[i - 1]) t++;
16             else
17             {
18                 if (t > maxt) maxt = t;
19                 t = 1;
20             }
21         }
22         if (t > maxt) maxt = t;
23         if (k > 1) cout << endl;
24         cout << maxt << endl;
25         for (int i = 0; i < maxt; i++)
26         {
27             for (int j = i; j < n; j += maxt)
28             {
29                 if (j == i) cout << dm[j];
30                 else cout <<   << dm[j];
31             }
32             cout << endl;
33         }
34         k++;
35     }
36     return 0;
37 }
View Code

 

2、Uva 11384 - Help is needed for Dexter

  题意:给出N,即有1~N个数,每个数的大小为1~N,每次选取剩下的若干个数,然后对于所有所选数字,减去选取数字中的某个数字。求最小的操作数,使得最后每个数为0.

  思路:每次二分操作,对于右侧的数字减去中间的那个数,结果为1~m,0~m(m+1);不断重复,最小的操作数即为log2(N)+1

技术分享
 1 #include <cmath>
 2 #include<iostream>
 3 using namespace std;
 4 int main()
 5 {
 6      int n;
 7      while (cin>>n)
 8      {
 9          cout << (int)log2(n) + 1 << endl;
10      }
11      return 0;
12 }
View Code

3、UVA 10795 A Different Task(汉诺塔递归)

  题意:给出汉诺塔的一个初始局面(对于n个盘子(编号大的盘子大),给出其所在柱子编号1或2或3),再给出一个目标局面,求移动次数。

  思路:从编号大的开始考虑,如果其初始位置a和目标位置c相同,则不移动;否则,设此时盘子编号为k,中间局面为k号盘子在a位置,1~k-1号盘子在6-a-c位置。则操作数为f(start,k-1,6-a-c)+f(final,k-1,6-a-c)+1,即从初始局面到中间局面的移动次数+目标局面到中间局面的移动次数+1(移动第k个盘子)(start和final分别为存储初始和目标位置的数组)。对于f(P,i,fnl),如果P[i]==fnl,则f(P,i,fnl)=f(P,i-1,fnl);否则,需要把前i-1个盘子移到6-P[i]-fnl号柱子上做中转(次数为f(P,i-1,6-P[i]-fnl)),然后把i号盘子移到fnl号柱子(次数为1),最后把前i-1号盘子移到fnl上(次数为2^(i-1)-1),即f(P,i,fnl)=f(P,i-1,6-P[i]-fnl)+2^(i-1).

 

技术分享
 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 long long f(int* P, int i, int final)
 5 {
 6     if (i == 0) return 0;
 7     if (P[i] == final) return f(P, i - 1, final);
 8     return f(P, i - 1, 6 - P[i] - final) + (1LL << (i - 1));
 9 }
10 
11 const int maxn = 60 + 10;
12 int n, start[maxn], finish[maxn];
13 
14 int main()
15 {
16     int Case = 0;
17     while (cin>>n,n!=0)
18     {
19         for (int i = 1; i <= n; i++) cin>>start[i];
20         for (int i = 1; i <= n; i++) cin>>finish[i];
21         int k = n;
22         while (k >= 1 && start[k] == finish[k]) k--;
23 
24         long long ans = 0;
25         if (k >= 1)
26         {
27             int other = 6 - start[k] - finish[k];
28             ans = f(start, k - 1, other) + f(finish, k - 1, other) + 1;
29         }
30         printf("Case %d: %lld\n", ++Case, ans);
31     }
32     return 0;
33 }
View Code

 

4、UVa 11520 Fill the Square

  题意:给出一个n*n的图,初始时图里存放若干大写字母,其他为空(记为‘.‘),之后往里面空的地方存放大写字母,要求有公共边的两个字母不相同,同时最后存放结束时从上到下,从左到右的字典序最小。

  思路:对于每个‘.‘,判断应填入的大写字母即可。

技术分享
 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 char m[15][15];
 5 int n;
 6 void Fill(int r, int c)
 7 {
 8     for (char C = A; C <= Z; C++)
 9     {
10         if (r - 1 >= 0 && m[r - 1][c] == C) continue;
11         else if (c - 1 >= 0 && m[r][c - 1] == C) continue;
12         else if (c + 1 < n&&m[r][c + 1] == C) continue;
13         else if (r + 1 < n&&m[r + 1][c] == C) continue;
14         m[r][c] = C;
15         return;
16     }
17 }
18 int main()
19 {
20     int Case=1,N;
21     cin >> N;
22     while (N--)
23     {
24         cin >> n;
25         for (int i = 0; i < n; i++)
26         {
27             for (int j = 0; j < n; j++) cin >> m[i][j];
28         }
29         for (int i = 0; i < n; i++)
30         {
31             for (int j = 0; j < n; j++)
32             {
33                 if (m[i][j] == .) Fill(i, j);
34             }
35         }
36         printf("Case %d:\n", Case++);
37         for (int i = 0; i < n; i++)
38         {
39             for (int j = 0; j < n; j++) cout << m[i][j];
40             cout << endl;
41         }
42     }
43     return 0;
44 }
View Code

 



以上是关于思维专题(不定期更新)的主要内容,如果未能解决你的问题,请参考以下文章

搜索专题(不定期更新)

最短路专题(不定期更新)

排列专题(不定期更新)

贪心专题(不定期更新)

无法使用 ArrayObjectAdaptor 的 clear() 和 addAll() 刷新/更新浏览片段

Ansible 专题学习