UVa 10132 & ZOJ 1832 & HOJ 1538 - File Fragmentation

35 篇文章 0 订阅
26 篇文章 0 订阅

传送门: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;
}






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值