标签:超时 form can lin which 空格 并查集 lib 没有
转自:https://www.cnblogs.com/yinbiao/p/9464390.html
题目: http://www.fjutacm.com/Contest.jsp?cid=870#P3
这题真的搞得我头痛,可能是我对并查集还没有深刻的理解吧
Five hundred years later, the number of dragon balls will increase unexpectedly, so it‘s too difficult for Monkey King(WuKong) to gather all of the dragon balls together.
五百年后,龙珠的数量会出乎意料地增加,所以悟空很难把所有的龙珠聚集在一起。
His country has N cities and there are exactly N dragon balls in the world. At first, for the ith dragon ball, the sacred dragon will puts it in the ith city. Through long years, some cities‘ dragon ball(s) would be transported to other cities. To save physical strength WuKong plans to take Flying Nimbus Cloud, a magical flying cloud to gather dragon balls.
他的国家有N个城市,世界上正好有N个龙珠。首先,为了第i个龙珠,神圣的龙会把它放在第i个城市。经过漫长的岁月,一些城市的龙珠会被运送到其他城市。为了节省体力,悟空计划乘飞天云,一种神奇的飞天云来收集龙珠。
Every time WuKong will collect the information of one dragon ball, he will ask you the information of that ball. You must tell him which city the ball is located and how many dragon balls are there in that city, you also need to tell him how many times the ball has been transported so far.
每次悟空收集一个龙珠的信息,他都会问你那个龙珠的信息。你必须告诉他球在哪个城市,在那个城市有多少个龙珠,你还需要告诉他球已经被运送了多少次。
输入的第一行是一个正整数T(0 < T <= 100)。
对于每种情况,第一行包含两个整数:N和Q (2 < N <= 10000, 2 < Q <= 10000)。
下列Q行中的每一行都包含一个事实或一个问题,其格式如下:
int find(int x) // 可将递归分为 两个过程 { int a = x; while (p[x] != x) // 搜索的过程 x = p[x]; while (a != x) // 回溯的过程 { int t = p[a]; p[a] = x; a = t; } return x; } int Find(int x) { if (p[x] != x) p[x] = Find(p[x]); return p[x]; }
find 函数可以要实现两个功能 ① 找到根结点 ② 压缩路径
函数实现可以有两种方法 ① 循环 ② 递归
就是在做这个时,我第一次想到,可以将递归分为两部分 ① 调用自己之前的代码 ② 调用自己之后的代码
愚以为,第一部分 是 搜索 实现找到 根结点 的功能 ;第二部分是 回溯 实现 压缩路径 的功能
想法一,之前打算构造一个 mov 数组,在 join 函数连接两个点的时候,让移动的那个城市 id ,mov[id]++,
后发现 当别的点移动时,是会带动集合的点也跟着移动的,这样子,其他点就没有记录到
想法二,还是在 join 函数,连接两个点之前,构造一个函数,让所有指向这个点的 点的mov++, 结果超时了
超时代码:
void fun(int x) { for (int i = 0; i <= n; i++) { if (p[i] == x) mov[i]++; } } void join(int x, int y) { x = find(x), y = find(y); if (x == y) return; fun(x); // p[x] = y; num[y] += num[x]; }
想法三,在想法一的基础上,加一个函数,在查询时,直接让 x 的所有父节点的mov[] 加起来,结果 wa, 原因:忘记被压缩路径了,找不回去了
错误代码
int move(int x) { int sum = 0, a = x; while (p[x] != x) { sum += mov[x]; x = p[x]; } sum += mov[x]; return sum; } void join(int x, int y) { x = find(x), y = find(y); if (x == y) return; p[x] = y; num[y] += num[x]; mov[x]++; } if (str[0] == ‘Q‘) { scanf("%d", &x); int k = find(x); printf("%d %d %d\n", k, num[k], mov[x]); }
所以,我就直接百度了,?乛?乛? (●´∀`●)
是基于我对想法一,利用 find 的回溯对其他点进行处理
说实话,由于没解释我这个代码直接看了一天,才理解,现在已然是在熬夜了
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #define N 10005 int p[N], num[N], mov[N]; int n, m; int find(int x) { if (p[x] != x) { int t = p[x]; p[x] = find(p[x]); mov[x] += mov[t]; } return p[x]; } void join(int x, int y) { x = find(x), y = find(y); if (x == y) return; p[x] = y; num[y] += num[x]; mov[x]++; } int main(void) { int t; scanf("%d", &t); int ci = 0; while (t--) { scanf("%d%d", &n, &m); for (int i = 0; i <= n; i++) { p[i] = i; num[i] = 1; mov[i] = 0; } printf("Case %d:\n", ++ci); char str[10]; while (m--) { scanf("%s", str); int x, y; if (str[0] == ‘T‘) { scanf("%d%d", &x, &y); join(x, y); } if (str[0] == ‘Q‘) { scanf("%d", &x); int k = find(x); printf("%d %d %d\n", k, num[k], mov[k]); } } } system("pause"); return 0; }
========== ======= ======= ====== ====== ===== ==== === == =
尘曲 七堇年
凡心所向,素履所往; 生如逆旅,一苇以航。
稣合于言,安之若素; 自言自语,无喜无悲。
凡心所向,素履所往; 生如逆旅,一苇以航。
三月桃花,四月欢唱; 两人一马,明日故乡。
流浪陌路,暖然绯凉; 写意人生,相识一场。
不关此世,不负己心; 我自倾杯,且君随意。
标签:超时 form can lin which 空格 并查集 lib 没有
原文地址:https://www.cnblogs.com/asdfknjhu/p/12528457.html