kungbin专题五 并查集 POJ1984 Navigation Nightmare

题意:
一个平面上有n个点,给出m个关系:u,v,s,u和v表示一个点的编号,s表示的是v在u的什么方向(东西南北)。然后k个询问:u,v,index,index表示的是在第index个关系之前的信息(包括第index个关系)能不能计算出u和v之间的哈曼顿距离,如果不能输出-1.
题解:
关系并查集,公式跟食物链差不多,只是这个变成了两个关系x,y,用x表示东西方向的距离,用y表示北南的方向,因为是询问是按index问的,那么我们要先存下询问的数据,然后再跑m个关系。我做这里被坑的点有,询问中的u,v不能放进并查集,会影响往后的并查集的距离的正确性,想一下,因为询问的u,v之间是没距离的,再加上如果他们之间不是同一个祖宗的话,就会更新关系,那么跑后面的有距离的关系的话就会出现因为他们已经是同一个祖宗已经是在同一个根了,不用更新关系的情况,从而影响了正确的输出,其他的没什么了。两份代码,一份我的挫代码(让我找到坑点),另一份是我第二天晚上写的。
还有一点就是,那个hit最后一句。。。你确定不是(location 6 is 3 units north and 7 west of 2, so the distance is 10.)?

//挫代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
const int MAXN=4e4+7;
struct node1
{
    int u,v,l;
    char s[5];
}a[MAXN];
struct node2
{
    int u,v,x,num;
}q[MAXN];
struct node3
{
    int f;
    int s,x;
}c[MAXN];
int ans[MAXN];
int n,m,k;
void init()
{
    memset(ans,0,sizeof(ans));
    for(int i=1;i<=n;i++)
    c[i].f=i,c[i].s=0,c[i].x=0;
}
int find(int p)
{
    while(p!=c[p].f)
    {
        int temp=c[p].f;
        c[p].f=find(temp);
        c[p].s=c[p].s+c[temp].s;
        c[p].x=c[p].x+c[temp].x;
        p=c[p].f;
    }
    return p;
}
int Union(int p,int q,int s,int x,bool flag)//后面这个标记表示进去的是询问的数据还是路线的数据,询问的数据不更新并查集,因为会影响并查集的正确数据,导致后面的数据和判断出错。 
{
    int P=find(p);
    int Q=find(q);
    if(P==Q)
    {
        int len=abs(c[q].s-c[p].s)+abs(c[q].x-c[p].x);
        return len;
    }
    else
    {
        if(flag)
        return -1;
        c[Q].f=P;
        c[Q].s=c[p].s+s-c[q].s;
        c[Q].x=c[p].x+x-c[q].x;
    }
    return -1;
}
bool cmp(node2 a1,node2 b1)
{
    return a1.x<b1.x;
}
int main() 
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=1;i<=m;i++)
        scanf("%d%d%d%s",&a[i].u,&a[i].v,&a[i].l,&a[i].s);
        scanf("%d",&k);
        for(int i=1;i<=k;i++)
        scanf("%d%d%d",&q[i].u,&q[i].v,&q[i].x),q[i].num=i;
        sort(q+1,q+1+k,cmp);
        int j=1;
        for(int i=1;i<=m;i++)
        {
            int l;
            if(a[i].s[0]=='E')
            l=a[i].l,Union(a[i].u,a[i].v,0,l,0);
            else if(a[i].s[0]=='W')
            l=-a[i].l,Union(a[i].u,a[i].v,0,l,0);
            else if(a[i].s[0]=='N')
            l=a[i].l,Union(a[i].u,a[i].v,l,0,0);
            else if(a[i].s[0]=='S')
            l=-a[i].l,Union(a[i].u,a[i].v,l,0,0);   
            while(q[j].x==i&&j<=k)
            {
                ans[q[j].num]=Union(q[j].u,q[j].v,0,0,1);
                j++;
            }   
        }
        for(int i=1;i<=k;i++)
        printf("%d\n",ans[i]);
    }
}
//这个好点
#include<stdio.h>
#include<string.h>
#include<math.h> 
#include<algorithm>
using namespace std;
const int MAXN=4e4+7;
struct node1
{
    int u,v;
    int l;
    char s[5];
}a[MAXN];
struct node2
{
    int u,v,id,num;
}q[MAXN];
struct node
{
    int f,x,y;
}c[MAXN];
int n,m,k;
int ans[MAXN];
void init()
{
    memset(ans,0,sizeof(ans));
    for(int i=1;i<=n;i++)
    c[i].f=i,c[i].x=0,c[i].y=0;
}
int find(int p)
{
    while(p!=c[p].f)
    {
        int temp=c[p].f;
        c[p].f=find(temp);
        c[p].x=c[p].x+c[temp].x;
        c[p].y=c[p].y+c[temp].y;
        p=c[p].f;
    }
    return p;
}
int Union(int p,int q,int x,int y)
{
    int P=find(p);
    int Q=find(q);
    if(P==Q)
    {
        int len=abs(c[q].y-c[p].y)+abs(c[q].x-c[p].x);
        return len;
    }
    else
    {
        c[Q].f=P;
        c[Q].y=c[p].y+y-c[q].y;
        c[Q].x=c[p].x+x-c[q].x;     
    }
    return -1;
}
bool cmp(node2 a1,node2 b1)
{
    return a1.id<b1.id;
}
int main() 
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=1;i<=m;i++)
        scanf("%d%d%d%s",&a[i].u,&a[i].v,&a[i].l,a[i].s);
        scanf("%d",&k);
        for(int i=1;i<=k;i++)
        scanf("%d%d%d",&q[i].u,&q[i].v,&q[i].id),q[i].num=i;
        sort(q+1,q+1+k,cmp);
        int j=1;        
        for(int i=1;i<=m;i++)
        {
            int x=0,y=0;
            if(a[i].s[0]=='E')
            x=a[i].l;
            else if(a[i].s[0]=='W')
            x=-a[i].l;
            else if(a[i].s[0]=='N')
            y=a[i].l;
            else if(a[i].s[0]=='S')
            y=-a[i].l;          
            Union(a[i].u,a[i].v,x,y);
            while(q[j].id==i&&j<=k)
            {
                int P=find(q[j].u);
                int Q=find(q[j].v);
                if(P!=Q)
                ans[q[j].num]=-1;
                else
                ans[q[j].num]=abs(c[q[j].v].y-c[q[j].u].y)+abs(c[q[j].v].x-c[q[j].u].x);
                j++;
            }
        }
        for(int i=1;i<=k;i++)
        printf("%d\n",ans[i]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值