传送门:UVa UVa 10132 & ZOJ 1832 & HOJ 1538 - File Fragmentation
ZOJ UVa 10132 & ZOJ 1832 & HOJ 1538 - File Fragmentation
题意:好几份放在盘子上的文件被打碎了(请原谅我苍白的表述XD),每个文件都被打碎成两部分,所有文件都是一样的。让我们输出文件的原来面貌。也就是说所有的碎片都可以两两组合成我们的答案。
这题纠结了一天了,从昨晚十点左右看到题目,想了一个来小时没思路,然后就看动漫去了。。
早上英语课又拿出来想。
其实思路很简单,但是我越想越“乱”。。
一开始打算把文件按长度排序后一份头一份尾地拼接,可是越想越有一种烦躁的感觉。。
中午吃饭时突然想到,一份固定长度的碎片肯定有一个对应的另一半,所以只要拿出长度最长的那个碎片,再用长度最短的碎片一份一份去拼就行,答案肯定在它们中间。
所以理一下思路吧:
1.如何得到原本的文件?
拿出一份长度最长的文件,然后把所有的长度最短的文件和它拼接(接前面&接后面),原件就在它们中间。
2.如何判断这个是原件?
拼接起来以后,用其他的碎片两两拼,可以拼起来的就标记为1。到最后,如果标记全部是1的,说明全部碎片都可以拼起来,输出,反之则不能,继续第一步。
但是这个方法有个缺陷:每次验证是否为原件前都要重置一遍vis数组,我觉得大部分时间肯定浪费在这里了,看着很不爽。。。应该有更好的解决办法。感觉这种我的这种方法就纯属暴力。。
ZOJ & HOJ的题目小小地改了一下,代码在后面。
I. UVa
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> using namespace std; const int MAXN = 300; string str[MAXN]; int vis[MAXN], len, n; bool Scan(string temp); bool cmp(string a, string b) { return a.size() < b.size(); } int main() { //freopen("input.txt", "r", stdin); int T, i, j; scanf("%d%*c", &T); getchar(); while (T--) { n = 0; while (getline(cin, str[n])) { if (str[n].size() == 0) break; else n++; } sort(str, str + n, cmp); for (i = 0; str[i].size() == str[0].size(); i++) { memset(vis, 0, sizeof(vis)); string temp = str[i] + str[n - 1]; bool flag = Scan(temp); if (flag) { cout << temp << endl; break; } memset(vis, 0, sizeof(vis)); temp = str[n - 1] + str[i]; //反着拼 flag = Scan(temp); if (flag) { cout << temp << endl; break; } } } return 0; } bool Scan(string temp) { int k = 0, i, j; bool flag = false; for (i = 0; i < n; i++) { for (j = n - 1; j >= 0; j--) { if (!vis[i] && !vis[j] && (str[i] + str[j] == temp || str[j] + str[i] == temp)) { vis[i] = vis[j] = 1; break; } } } for (i = 0; i < n; i++) if (!vis[i]) return false; return true; }
II.HOJ & ZOJ
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> using namespace std; const int MAXN = 150; string str[MAXN]; int vis[MAXN], len, n; bool Scan(string temp); bool cmp(string a, string b) { return a.size() < b.size(); } int main() { //freopen("input.txt", "r", stdin); int T, i, j; while (getline(cin, str[0])) { n = 1; while (getline(cin, str[n])) { if (str[n].size() == 0) break; else n++; } sort(str, str + n, cmp); len = str[n - 1].size() + str[0].size(); for (i = 0; str[i].size() == str[0].size(); i++) { memset(vis, 0, sizeof(vis)); string temp = str[i] + str[n - 1]; bool flag = Scan(temp); if (flag) { cout << temp << endl; break; } memset(vis, 0, sizeof(vis)); temp = str[n - 1] + str[i]; flag = Scan(temp); if (flag) { cout << temp << endl; break; } } } return 0; } bool Scan(string temp) { int k = 0, i, j; bool flag = false; for (i = 0; i < n; i++) { for (j = n - 1; j >= 0; j--) { if (!vis[i] && !vis[j] && str[i] + str[j] == temp || str[j] + str[i] == temp) { vis[i] = vis[j] = 1; break; } } } for (i = 0; i < n; i++) if (!vis[i]) return false; return true; }