1、contact
这题估计是丢俺老脸的题,因为俺就直接枚举了。唯一的trick是对于 01, 001这样的字符串,计算hash值的时候,需要记得转换为 101, 1001这样的形式,不然肯定就混淆了,所以直接上代码吧,应该好懂。
-
/*
-
ID:fairyroad
-
LANG:C++
-
TASK:contact
-
*/
-
#include <fstream>
-
#include <string>
-
#include <algorithm>
-
using namespace std;
-
-
ifstream fin("contact.in");
-
ofstream fout("contact.out");
-
-
#define MAXNUM 16385 // 1<<14 + 1
-
size_t A, B, N;
-
string s;
-
-
struct Sequence {
-
int cnt;
-
string str;
-
Sequence() : cnt(0), str("") {}
-
Sequence(int c, string s) : cnt(c), str(s) {}
-
bool operator>(const Sequence& other) const {
-
if(cnt > other.cnt) return true;
-
if(cnt == other.cnt) {
-
if(str.length() < other.str.length()) return true;
-
else if (str.length() == other.str.length()) return str < other.str;
-
else return false;
-
}
-
return false;
-
}
-
};
-
-
Sequence hash[MAXNUM];
-
-
int main()
-
{
-
fin >> A >> B >> N;
-
string line;
-
while(getline(fin, line))
-
s+=line;
-
-
int num;
-
size_t j, k;
-
-
for(size_t i = A; i <= B; ++i)
-
{
-
for(j = 0 ; j + i <= s.size(); ++j)
-
{
-
num = 1; // 注意这里,关键就在这里了
-
for(k = j; k - j < i; ++k)
-
{
-
num <<= 1;
-
if(s[k] == '1') num += 1;
-
}
-
-
if(!hash[num].cnt)
-
{
-
hash[num].cnt = 1;
-
hash[num].str = string(s, j, i);
-
}
-
else
-
hash[num].cnt ++;
-
}
-
}
-
-
sort(hash, hash + MAXNUM, greater<Sequence>()); // 可以在前面的循环中就建立一个大小为N的堆
-
-
int linenum = 1, precnt = hash[0].cnt;
-
fout << hash[0].cnt << '\n' << hash[0].str;
-
size_t i, outline = 1;
-
-
for(i = 1; i < MAXNUM; ++i)
-
{
-
if(!hash[i].cnt) break;
-
-
if(hash[i].cnt == precnt)
-
{
-
if(linenum < 6)
-
{
-
linenum ++;
-
fout << ' ' << hash[i].str;
-
}
-
else
-
{
-
linenum = 1;
-
fout << '\n' << hash[i].str;
-
}
-
}
-
else
-
{
-
if(outline == N) break;
-
precnt = hash[i].cnt;
-
fout << '\n' << hash[i].cnt << '\n' << hash[i].str;
-
linenum = 1;
-
outline++;
-
}
-
}
-
-
fout << endl;
-
return 0;
-
}
2、Stamps
这题我比较喜欢,我想凡是做过ACM的多少都有点似曾相识的感觉,因为这题多少可以算是背包问题的变种,而背包问题几乎是ACM必修课了,下面直接给出DP公式:
f(m) =
1. dp(m) if dp(m) is set
2. min(dp(m-s(i)) + 1, for i in [0, n)
因为2中有一个循环,所以复杂度是O(N*M)。
-
/*
-
ID:fairyroad
-
LANG:C++
-
TASK:stamps
-
*/
-
#include <fstream>
-
using namespace std;
-
-
ifstream fin("stamps.in");
-
ofstream fout("stamps.out");
-
-
int k, n; // 可以使用的邮票的张数,邮票种类
-
int s[50];
-
int dp[10000*200+1];
-
-
int main()
-
{
-
fin >> k >> n;
-
int i, min, curr = 0, tmp;
-
for(i = 0;i < n; ++i)
-
{
-
fin >> s[i];
-
dp[s[i]] = 1; // 这些面值可以直接获取
-
}
-
-
while(true)
-
{
-
++curr;
-
if(dp[curr] != 0) continue; // 注意curr是从1开始升上去的
-
-
min = k+1;
-
for( i = 0; i < n; ++i)
-
{
-
tmp = curr-s[i];
-
if(tmp <= 0) continue; // 输入的邮票面值集合不一定是从小到大排好序的
-
if(dp[tmp] + 1 < min)
-
min = dp[curr-s[i]] + 1;
-
}
-
-
if(min > k) break;
-
-
dp[curr] = min;
-
}
-
-
fout << curr-1 << endl;
-
return 0;
-
}
老生常谈,大多数情况下,动态规划是缩时利器,虽然空间上会打点折扣。而DP的关键就是要写出那个递推公式。一句八卦就是,如果你熟练掌握了动态规划,大多数情况下,面试中你可以藐视众多面试题~