HDU 4829 Information [带权并查集]【数据结构】

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4829
——————————————————————————–.
Information

Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 367 Accepted Submission(s): 61

Problem Description
军情紧急,我们需要立刻开发出一个程序去处理前线侦察兵发回的情报,并做出相应的分析。现在由你负责其中的一个子模块,你需要根据情报计算出敌方坦克的位置。
当敌方坦克静止时,侦察兵会尽力估算出它们之间的位置,而每当敌方坦克移动时,侦察兵都会记录下坦克新的位置并向你报告。每个坦克的位置可以由一个二维整数坐标来描述。
前线发回的情报有四种格式:
1 A B X Y
表示A坦克移动到了与B坦克的相对位置是(X,Y)的地方,即XA = XB + X,YA=YB+Y。
2 A X Y
表示A坦克移动到了绝对位置是(X,Y)的地方,即XA = X,YA = Y。
3 A B X Y
表示发现了A坦克与B坦克的相对位置是(X,Y),即XA = XB + X,YA=YB+Y。
4 A X Y
表示发现了A坦克的绝对位置是(X,Y),即XA = X,YA = Y。
我们需要你对于如下两种询问及时做出回应:
5 A B
表示询问A坦克与B坦克的相对位置是多少,即分别求出XA - XB 以及YA -YB。
6 A
表示询问A坦克的绝对位置是多少,即求出XA 和YA。
其中A和B代表的是任意的一个坦克的编号,(X,Y)表示了坦克的二维坐标。你可以假设初始时刻我们对于敌方任何坦克的位置都一无所知,在此之后坦克的每一次移动都被侦察兵侦察到了。
请注意两个坦克的坐标有可能相同。

Input
输入的第一行是一个整数T(T < 1000),表示共有T组数据。
对于每组数据,第一行有一个整数N,表示这组数据有N次查询。接下来的每行表示一次查询,每次查询第一个数字代表是哪种询问,询问的格式详见上文。
数据范围:
0 < N <=100000,0 < A,B<=N 且 A<>B,X和Y都是整数且 0 <=X,Y<=10000 .
测试数据中98%的数据N不超过50。

Output
对于每组数据,首先需要输出单独一行”Case #?:”,其中问号处应填入当前的数据组数,组数从1开始计算。
对于每一个类型(1)或者(2)的询问,请把它们加入到你的记录中。
对于每一个类型(3)或者(4)的询问,如果与之前记录的内容有矛盾,请输出”REJECT”并将这个情报忽略掉,如没有矛盾,请把它们加入到你的记录中。
对于每一个类型(5)或者(6)的询问,如果根据之前的记录能推出结论,请输出两个整数X和Y,两个整数之间有一个空格;如果不能推出结论,请输出”UNKNOWN”。输出的所有信息都不包括引号。

Sample Input
2
7
1 1 2 3 4
2 3 4 5
3 4 5 2 1
4 6 2 2
3 2 4 6 2
5 4 1
6 3
6
6 3
4 3 2 2
6 3
2 4 2 3
5 3 4
3 3 4 1 2

Sample Output
Case #1:
-9 -6
4 5
Case #2:
UNKNOWN
2 2
0 -1
REJECT

Source
2014年百度之星程序设计大赛 - 初赛(第一轮)

——————————————————————————–.

解题思路:

就是维护一堆数据之间的关系,读完题很容易想到带权并查集,权值为两个点之间的相对距离.但是在维护上不是怎么好维护啊。

不好维护的地方
1坦克移动到(x,y)时,那么之前的位置变化产生的相对关系就错了,但是并查集是不可逆向操作的.
2.我们仅表示的相对位置关系,但是对于绝对位置的坐标求解如何考虑.
3,一个点的相对位置比如a相对b的位置是[x,y],但是a,b的位置还不知道的情况下,我们怎么处理这个值.

解决;
1,放弃这个点a,在创建一个新的点p来表示a,映射a->p进行运算即可.
2,我们可以多创建一个点来表示原点(是其他所有点的父节点),那么任何一个点的绝对位置都是与原地的相对位置.
3,假设存在这样的情况,我们可以假设b的坐标是一个随意的值(0,0)就行.

解决了上述几个问题,这道题就不难解决了.

附本题代码
—————————————————————.

#include <bits/stdc++.h>
using namespace std;
const int    N   = 100000*2+7;
/***********************************************************************/
int pre[N],h[N],hh;
struct node {
    int x,y;
}p[N];
int findi(int x){
    if(pre[x]==x) return x;
    int r = findi(pre[x]);
    p[x].x+=p[pre[x]].x;
    p[x].y+=p[pre[x]].y;
    pre[x]=r;
    return r;
}
void join(int x,int y,int X,int Y){
    int fx = findi(x),fy = findi(y);
    pre[fx]=fy;
    p[fx].x=p[y].x+X-p[x].x;
    p[fx].y=p[y].y+Y-p[x].y;
    return ;
}
void creat(int now){
    h[now]=++hh;
    pre[hh]=hh;
    p[hh].x=0;
    p[hh].y=0;
}
int main(){
    int _,n,m,kcase = 0;
    scanf("%d",&_);
    while(_--){

        int n;
        scanf("%d",&n);printf("Case #%d:\n",++kcase);
        hh=-1;
        for(int i=0;i<=n;i++) creat(i),h[i]=i;
        for(int i=n+1;i<=(n<<1);i++) p[i].x=p[i].y=0;
        int x,y,a,b,op;
        for(int i=1;i<=n;i++){
            scanf("%d",&op);b=0;
            if(op==1||op==2){
                if(op==1)scanf("%d%d%d%d",&a,&b,&x,&y);
                else     scanf("%d%d%d",&y);
                creat(a);
                join(h[a],h[b],x,y);
            }
            else if(op==3||op==4){
                if(op==3)scanf("%d%d%d%d",&y);
                a=h[a],b=h[b];
                if(findi(a)==findi(b)){if(x!=p[a].x-p[b].x||y!=p[a].y-p[b].y)puts("REJECT");}
                else join(a,y);
            }
            else {
                if(op==5)scanf("%d%d",&b);
                else     scanf("%d",&a);
                a=h[a],b=h[b];
                if(findi(a)!=findi(b)) {puts("UNKNOWN");continue; }
                else printf("%d %d\n",p[a].x-p[b].x,p[a].y-p[b].y);
            }
        }

    }
    return 0;
}

相关文章

【啊哈!算法】算法3:最常用的排序——快速排序       ...
匿名组 这里可能用到几个不同的分组构造。通过括号内围绕的正...
选择排序:从数组的起始位置处开始,把第一个元素与数组中其...
public struct Pqitem { public int priority; ...
在编写正则表达式的时候,经常会向要向正则表达式添加数量型...
来自:http://blog.csdn.net/morewindows/article/details/6...