PKU 1984 Navigation Nightmare dfs+并查集

来源:互联网 发布:mac 查看系统版本 编辑:程序博客网 时间:2024/05/01 00:48

    由于询问时需要询问到第几步时的情况,所以先把所有数据都存起来,我是用一个结构体node1来保存每条边的端点和方向,用node2来表示Qerry的问题,以便按照I的大小排序,用node3来表示个个点的笛卡尔坐标,来计算Manhattan距离。

    dfs的运用时用来标志每个点的笛卡尔坐标,可以给任何一个点赋值为(0,0)由于图是连通的,深搜一遍遍可以得到各个点的相对坐标,这里用一个vector来构造一个图。

    按照I的大小从小到大排序,再进行并查集运算,此时有

    int temp = 1;
    for( i=1; i<=M; i++ ){
         link( find( ans[i].u ) , find( ans[i].v ) );
         if( bns[temp].I == i ){
             if( find( bns[temp].f1 ) == find( bns[temp].f2 )  ){  //判断是否属于一个集合
                 printf( "%d/n", dist( bns[temp].f1 , bns[temp].f2 ) );
             }
             else
                 puts( "-1" );

             temp ++;
             if( bns[temp].I == i ) i--;  //这里要注意,因为I的值可能相同,如果不停增加i,则I相同的会给忽略
         }
    }

AC code:

Memory: 6260K Time: 969MS

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdio>
using namespace std;

const int NMAX = 40005;
struct node1{
    int u,v,dis;
    char c;
};
struct node2{
    int f1,f2,I;
};
struct node3{
    int x,y;
};
struct node4{
    int next,length;
    char pos;  
};
int N,M,K,i,j;
node1 ans[NMAX];
node2 bns[NMAX];
node3 cns[NMAX];
bool used[NMAX];
vector<node4> gif[NMAX];
int father[NMAX],rank[NMAX];

bool cmp( const node2 x , const node2 y )
{
    return x.I < y.I;
}

char turn ( char x )
{
    if( x == 'N' )return 'S';
    if( x == 'W' )return 'E';
    if( x == 'E' )return 'W';
    if( x == 'S' )return 'N';
}

void makeset()
{
    for( i=1; i<=N; i++ ){
         father[i] = i;
         rank[i] = 0;
    }
}

int find( int x )
{
    if( x != father[x] )
        return father[x] = find( father[x] );
    return x;
}

void link ( int x , int y )
{
    if( rank[x] > rank[y] )
        father[y] = x;
    else {
        father[x] = y;
        if( rank[x] == rank[y] ) rank[y] ++;
    }
}

int dist( int fx , int fy )
{
    int a = abs( cns[fx].x - cns[fy].x );
    int b = abs( cns[fx].y - cns[fy].y );
    return a + b;
}

void dfs( int u )
{
    vector<node4>::iterator it;
    for( it = gif[u].begin(); it != gif[u].end(); it ++ ){
         node4 temp = *it;
         int v = temp.next;
         if( !used[ v ] ){
             char p = temp.pos;
             if( p == 'N' ){
                 cns[v].x = cns[u].x;
                 cns[v].y = cns[u].y + temp.length;
             }
             if( p == 'S' ){
                 cns[v].x = cns[u].x;
                 cns[v].y = cns[u].y - temp.length;
             }
             if( p == 'E' ){
                 cns[v].x = cns[u].x + temp.length;
                 cns[v].y = cns[u].y;
             }
             if( p == 'W' ){
                 cns[v].x = cns[u].x - temp.length;
                 cns[v].y = cns[u].y;
             }
             used[v] = true;
             dfs(v);
         }
    }
}

void slove()
{
    scanf( "%d %d", &N, &M );
    makeset();
    int root;
    for( i=1; i<=M; i++ ){
         scanf( "%d %d %d %c", &ans[i].u , &ans[i].v , &ans[i].dis , &ans[i].c );
         if( i == 1 ) root = ans[i].u;
         node4 temp;
         temp.length = ans[i].dis;
         temp.next = ans[i].v;
         temp.pos = ans[i].c;
         gif[ ans[i].u ].push_back( temp );
         temp.next = ans[i].u;
         temp.pos = turn( ans[i].c );
         gif[ ans[i].v ].push_back( temp );
    }
    memset( used , false , sizeof( used ) );
    cns[root].x = 0;
    cns[root].y = 0;
    used[root] = true;
    dfs( root );
    scanf( "%d", &K );
    for( i=1; i<=K; i++ )
         scanf( "%d %d %d", &bns[i].f1 , &bns[i].f2 , &bns[i].I );
    //sort( bns + 1 , bns + K + 1, cmp );
    int temp = 1;
    for( i=1; i<=M; i++ ){
         link( find( ans[i].u ) , find( ans[i].v ) );
         if( bns[temp].I == i ){
             if( find( bns[temp].f1 ) == find( bns[temp].f2 ) && used[ bns[temp].f1 ] && used[ bns[temp].f2 ] ){
                 printf( "%d/n", dist( bns[temp].f1 , bns[temp].f2 ) );//想想,这个used数组可以不要的,是为了标志图是否连通,但如果不连通的话,这道题很多坐标都dfs不到,所以加了也错,题目应该是说连通图吧,善哉善哉。
             }
             else
                 puts( "-1" );
             temp ++;
             if( bns[temp].I == i ) i--;
         }
    }
}

int main()
{
    slove();
    //system("pause");
    return 0;

原创粉丝点击