HOJ 3371 Connect the Cities

本题数据量有点大,暴力的结果是TLE。
读入用了scanf没用cin,不知道会不会TLE。
使用三个一维数组代替二维数组存储边,降低时间复杂度,如果细看的话也可以知道降低了内存消耗:m <= 25000, n * n <= 250000。
还有就是读入数据需要细心一点,基本就可以了。

#include
#include
using namespace std;
const int NN = 500 + 5, NM = 25000 + 5, INF = 99999999;
int f[NN], c1[NM], c2[NM], c3[NM];//f[NN]记录每个顶点的根节点,c三个一维数组代替二维数组存储边以降低时间复杂度

int find(int x)
{//寻找根节点
	if (x == f[x]) return x;
	f[x] = find(f[x]);
	return f[x]; 
}

int mer(int x, int y)
{//x和y所在的两个集合合并
	x = find(x);
	y = find(y);
	if (x != y)
		f[x] = y;
	return 1;
}

int main()
{
	int T, n, m, k, t, x, y, sum;//T为测试数据组数,sum记录最小花费,其他对应题目数据
	cin >> T;
	while (T--)
	{
		sum = 0;
		scanf("%d %d %d", &n, &m, &k);
		for (int i = 1; i <= n; i++)
			f[i] = i;//集合初始化
		for (int i = 1; i <= m; i++)
			scanf("%d %d %d", &c1[i], &c2[i], &c3[i]);//用三个一维数组进行存储,下面的计算降低时间复杂度
		for (int i = 0; i < k; i++)//输入细心一点就可以了
		{
			scanf("%d %d", &t, &x);
			while (t != 1)
			{
				scanf("%d", &y);
				mer(x, y);
				x = y;
				t--;
			}
		}
		while (1)
		{
			int min0 = INF, flag = 1;
			//如果用二维数组存储数据,使用Prime算法要用到双重for,加上while,时间复杂度是O(n^3),本题数据量大,会TLE
			for(int i = 1; i <= m; i++)
				if (min0 > c3[i] && find(c1[i]) != find(c2[i]) )//如果是if(find(c1[i]) != find(c2[i]) && min0 > c3[i]),先进行find会TLE
				{
					min0 = c3[i];
					x = c1[i];
					y = c2[i];
					flag = 0;
				}
			if (flag) break;
			sum += min0;
			mer(x, y);
		}

		int p = 1;
		for(int i = 2; i <= n; i++)//判断是否全连通
			if (find(i - 1) != find(i))//若并非全连通,必定存在相邻不同的根节点
			{
				p = 0;
				break;
			}
		if (p)
			cout << sum << endl;
		else
			cout << "-1" << endl;
	}
	return 0;
}

你可能感兴趣的:(HOJ 3371 Connect the Cities)