训练链接:http://acm.njupt.edu.cn/vjudge/contest/view.action?cid=173#overview
F题 Navigation Nightmare
Time Limit: 2000MS | Memory Limit: 30000K | |
Total Submissions: 4599 | Accepted: 1734 | |
Case Time Limit: 1000MS |
Description
F1 --- (13) ---- F6 --- (9) ----- F3
| |
(3) |
| (7)
F4 --- (20) -------- F2 |
| |
(2) F5
|
F7
Input
* Line 1: Two space-separated integers: N and M
* Lines 2..M+1: Each line contains four space-separated entities, F1,
F2, L, and D that describe a road. F1 and F2 are numbers of
two farms connected by a road, L is its length, and D is a
character that is either 'N', 'E', 'S', or 'W' giving the
direction of the road from F1 to F2.
* Line M+2: A single integer, K (1 <= K <= 10,000), the number of FB's
queries
* Lines M+3..M+K+2: Each line corresponds to a query from Farmer Bob
and contains three space-separated integers: F1, F2, and I. F1
and F2 are numbers of the two farms in the query and I is the
index (1 <= I <= M) in the data after which Bob asks the
query. Data index 1 is on line 2 of the input data, and so on.
Output
* Lines 1..K: One integer per line, the response to each of Bob's
queries. Each line should contain either a distance
measurement or -1, if it is impossible to determine the
appropriate distance.
Sample Input
7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6 1
1 4 3
2 6 6
Sample Output
13
-1
10
Hint
Source
#include
#include
int const MAX = 40005;
int fa[MAX], x[MAX], y[MAX];
int n, m, k;
char get[MAX][50];
void UF_set()
{
for(int i = 0; i <= n; i++)
{
fa[i] = i;
x[i] = y[i] = 0;
}
}
int Find(int nd)
{
if(nd == fa[nd])
return nd;
int tmp = fa[nd];
fa[nd] = Find(fa[nd]);
x[nd] += x[tmp];
y[nd] += y[tmp];
return fa[nd];
}
void Union(int a, int b, int dx, int dy)
{
int r1 = Find(a);
int r2 = Find(b);
if(r1 != r2)
{
fa[r2] = r1;
x[r2] = x[a] + dx - x[b];
y[r2] = y[a] + dy - y[b];
}
}
int abs(int a)
{
return a > 0 ? a : -a;
}
int dis(int x1, int x2, int y1, int y2)
{
return abs(x1 - x2) + abs(y1 - y2);
}
int main()
{
scanf("%d %d", &n, &m);
UF_set();
getchar();
for(int i = 0; i < m; i++)
gets(get[i]);
scanf("%d", &k);
int nd1, nd2, ct, cur = 0;
while(k--)
{
int a, b, d;
scanf("%d %d %d", &nd1, &nd2, &ct);
for(int i = cur; i < ct; i++)
{
int dx = 0, dy = 0;
char dir[2];
sscanf(get[i], "%d %d %d %s", &a, &b, &d, dir);
switch(dir[0])
{
case 'E': dx += d; break;
case 'W': dx -= d; break;
case 'N': dy += d; break;
case 'S': dy -= d; break;
}
Union(a, b, dx, dy);
}
cur = ct;
//这两步很重要,不只是找到r1和r2的根,还更新了x[],y[],同G题
int r1 = Find(nd1);
int r2 = Find(nd2);
if(r1 != r2)
printf("-1\n");
else
printf("%d\n", dis(x[nd1], x[nd2], y[nd1], y[nd2]));
}
}
G题 Cube Stacking
Time Limit: 2000MS | Memory Limit: 30000K | |
Total Submissions: 19686 | Accepted: 6888 | |
Case Time Limit: 1000MS |
Description
Input
Output
Sample Input
6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4
Sample Output
1
0
2
Source
题目链接:http://poj.org/problem?id=1988
题目大意:有n个操作,M a b相当于把编号为a的盘子放到编号为b的上面,注意这里不是插放,是把编号为a的那堆放在编号为b的那一堆的最上面
C a表示询问a下面有几个盘子
题目分析:带权并查集,把b当作a的根,需要三个数组fa[x]表示x的祖先,w[x]表示x到根的距离,cnt[x]表示已x为根的当前堆的数量,我们只需要不断维护w[]和cnt[]两个数组下面给出一组样例和程序执行的过程
7
r1 = Find(1) = 1;r2 = Find(6) = 6;(此时w[1] = 0,w[6] = 0);
fa[1] = 6(6为1的祖先); w[1] = cnt[6] = 1(1下面有1个,即6);
cnt[6] = cnt[1] + cnt[6] = 2(已6为根的堆的数量为2,即1和6);
r1 = Find(2) = 2;r2 = Find(4) = 4; (此时w[2] = 0,w[4] = 0);
fa[2] = 4(4为2的祖先); w[2] = cnt[4] = 1(2下面有1个,即4);
cnt[4] = cnt[4] + cnt[2] = 2(已4为根的堆的数量为2,即2和4);
r1 = Find(2) = 4(第二步时得到2的祖先为4);r2 = Find(6) = 6;fa[4] = 6(6为4的祖先);(此时w[2] = w[2] + w[4] = 1)
w[4] = cnt[6] = 2(4下面有2个,即1,6);
cnt[6] = cnt[6] + cnt[4] = 4(已6为根的堆的数量为4,即2,4,1,6);
C2询问2下面有几个,这时w[2] = 2显然不对,因为w[2] = w[2] + w[4]之前Find的时候w[4]的值为0,可是Union完w[4] = 2因此我们要更新w[2]的值,更新的方法就是Find(2)就可以了,因为Find函数中,对于当前的x递归找它的祖先,加上其祖先下面的个数
r1 = Find(5) = 5;r2 = Find(7) = 7; (此时w[5] = 0,w[7] = 0);
fa[5] = 7(7为5的祖先); w[5] = cnt[7] = 1 (5下面有1个,即7);
cnt[7] = cnt[7] + cnt[5] = 2(已7为根的堆的数量为2,即5和7);
r1 = Find(5) = 7;r2 = Find(6) = 6; fa[7] = 6(6为7的祖先); (此时w[5] = 1,w[7] = 0)
* w[7] = cnt[6] = 4 (7下面有4个,即2,4,1,6);
cnt[6] = cnt[6] + cnt[7] = 6(已6为根的堆的数量为6,即5,7,2,4,1,6);
C5询问5的下面有几个,显然5下面的个数为5到7的距离w[5] = 1加上7到6的距离w[7] = 4,这里我们必须Find(5),因为在Find(5)之前w[5]还等于1,*号操作更新了w[7],但没有更新w[5],所以要更新w[5]。即Find(5)更新完之后w[5] = w[5] + w[7] = 5,我们看此时的序列为 5 7 2 4 1 6,5下面确实有5个。
#include
int const MAX = 30005;
int fa[MAX], cnt[MAX], w[MAX];
void UF_set()
{
for(int i = 1; i <= MAX; i++)
{
fa[i] = i;
w[i] = 0; //下面都没有,初始化为0
cnt[i] = 1; //当前堆只有自身,初始化为1
}
}
int Find(int x)
{
if(x == fa[x])
return fa[x];
int tmp = fa[x];
fa[x] = Find(fa[x]);
w[x] += w[tmp];
return fa[x];
}
void Union(int a, int b)
{
int r1 = Find(a);
int r2 = Find(b);
if(r1 != r2)
{
fa[r1] = r2;
w[r1] = cnt[r2]; //r1下面的个数为r2的堆数
cnt[r2] += cnt[r1]; //r2的堆数要加上r1那堆的数量
}
}
int main()
{
int T, x, y;
char s[2];
scanf("%d", &T);
UF_set();
while(T--)
{
scanf("%s", s);
if(s[0] == 'M')
{
scanf("%d %d", &x, &y);
Union(x, y);
}
else
{
scanf("%d", &x);
//这里一定要在Find函数中更新一次w[x]的值
//可以通过样例4 M 1 6 M 2 4 M 2 6 C 2看出来
Find(x);
printf("%d\n", w[x]);
}
}
}
Time Limit: 10000MS | Memory Limit: 65536K | |
Total Submissions: 17156 | Accepted: 7214 |
Description
Input
Output
Sample Input
4 1 0 1 0 2 0 3 0 4 O 1 O 2 O 4 S 1 4 O 3 S 1 4
Sample Output
FAIL SUCCESS
Source
题目链接:http://poj.org/problem?id=2236
题目大意:有n台损坏的电脑,每两台之间可以通信的最大距离为d,给出n台电脑的坐标,两个操作,O x表示修复第x台
S x y表示询问x与y间能否访问。
题目分析:水题,修复了的标记一下,根据d的条件把能通信的放在一个集合里面,询问时如果根相同说明可以通信
#include
#include
int const MAX = 1005;
int fa[MAX], ok[MAX];
int n, d;
struct Point
{
int x, y;
int id;
}p[1005];
void UF_set()
{
for(int i = 1; i <= n; i++)
fa[i] = i;
}
int Find(int x)
{
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
void Union(int a, int b)
{
int r1 = Find(a);
int r2 = Find(b);
if(r1 != r2)
fa[r2] = r1;
}
int dis(int x1, int y1, int x2, int y2)
{
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
}
int main()
{
memset(ok, 0, sizeof(ok));
scanf("%d %d", &n, &d);
UF_set();
for(int i = 1; i <= n; i++)
{
scanf("%d %d", &p[i].x, &p[i].y);
p[i].id = i;
}
char s[2];
bool tmp = false;
int x, y;
while(scanf("%s %d", s, &x) != EOF)
{
if(s[0] == 'O')
{
ok[p[x].id] = 1;
for(int i = 1; i <= n; i++)
if(dis(p[x].x, p[x].y, p[i].x, p[i].y) <= (d * d) && ok[p[i].id])
Union(x, i);
}
else
{
scanf("%d", &y);
if(Find(x) == Find(y))
printf("SUCCESS\n");
else
printf("FAIL\n");
}
}
}
I题 Supermarket
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 9422 | Accepted: 4056 |
Description
Input
Output
Sample Input
4 50 2 10 1 20 2 30 1
7 20 1 2 1 10 3 100 2 8 2
5 20 50 10
Sample Output
80
185
Hint
Source
#include
#include
using namespace std;
int const MAX = 1e4 + 5;
int n, ans;
int fa[MAX];
struct PRODUCTS
{
int p, d;
}pr[MAX];
void UF_set()
{
for(int i = 0; i < MAX; i++)
fa[i] = i;
}
int Find(int x)
{
return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
void Union(int a, int b)
{
int r1 = Find(a);
int r2 = Find(b);
if(r1 != r2)
fa[r1] = r2; //这里不能反,必须把前一天做为当前天的根
}
int cmp(PRODUCTS a, PRODUCTS b)
{
return a.p > b.p;
}
int main()
{
while(scanf("%d", &n) != EOF)
{
UF_set();
ans = 0;
for(int i = 0; i < n; i++)
scanf("%d %d", &pr[i].p, &pr[i].d);
sort(pr, pr + n, cmp);
for(int i = 0; i < n; i++)
{
int curpos = Find(pr[i].d);
if(curpos)
{
ans += pr[i].p;
Union(curpos, curpos - 1);
}
}
printf("%d\n", ans);
}
}