poj 1556 线段相交+最短路

先利用线段相交,判断可以建立的边,然后求存最短路即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#define eps 1e-6
#define MAX 10007

using namespace std;


int n;
struct Point 
{
    double x , y;
}point[MAX][10];

int sig ( double d )
{
    return fabs(d) < eps ? 0 : d<0? -1 : 1 ;
}

double cross ( Point&o , Point &a , Point& b )
{
    return (a.x-o.x)*(b.y-o.y)-(b.x-o.x)*(a.y-o.y);
} 

bool segCross ( Point &a , Point &b , Point &c , Point &d )
{
    double s1,s2;
    int d1 , d2 , d3 , d4;
    d1 = sig(s1=cross(a,b,c));
    d2 = sig(s2=cross(a,b,d));
    d3 = sig(cross(c,d,a));
    d4 = sig(cross(c,d,b));
    if ((d1^d2)==-2 && (d3^d4)==-2)
        return 1;
    return 0;
}

struct edge
{
    int u,v,next;
    double w;
}e[MAX];

int head[MAX];
int cc = 0;

void add ( int u , int v , double w )
{
    e[cc].u = u;
    e[cc].v = v;
    e[cc].next = head[u];
    e[cc].w = w;
    head[u] = cc++;
}


bool check ( Point& a , Point &b , int begin , int end )
{
    for ( int i = begin+1 ; i < end ; i++ )
        for ( int j = 1 ; j < 6 ; j += 2 )
            if ( segCross ( a , b , point[i][j] , point[i][j+1] ) )
                return false;
    return true;
}

double dis ( Point& a , Point& b )
{
    return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));  
}

double way[MAX];
bool used[MAX];
void spfa ( int s = 1  , int v = 6*n+7  )
{
    queue<int> q;
    memset ( used , 0 , sizeof ( used ) );
    q.push ( s );
    used[s] = 1;
    for ( int i = s ; i <= v ; i++ )
        way[i] = 1e9;
    way[s] = 0;
    while ( !q.empty( ) )
    {
        int id = q.front();
        q.pop();
        used[id] = false;
        for ( int i = head[id] ; i != -1 ; i = e[i].next )
        {
            int v = e[i].v;
            if ( way[v] > way[id] + e[i].w )
            {
                way[v] = way[id] + e[i].w;
                if ( used[v] ) continue;
                used[v] = true;
                q.push ( v );
            }
        }
    }
}

int main ( )
{
    double x;
    while ( ~scanf ( "%d" , &n ) )
    {
        if ( n == -1 ) break; 
        cc = 0;
        memset ( head , -1 , sizeof ( head ) );
        for ( int i = 1 ; i <= n ; i++ )
        {
            scanf ( "%lf" , &x );
            for ( int j = 1 ; j <= 6 ; j++ )
            {
                point[i][j].x = x;
                if ( j == 1 ) point[i][j].y = 0.0;
                else if( j == 6 ) point[i][j].y = 10.0;
                else scanf ( "%lf" , &point[i][j].y ) ;  
            }
        }
        for ( int i = 1 ; i <= n ; i++ )
            for ( int j = 1 ; j <= 6 ; j++ )
                for ( int k = i+1 ; k <= n ; k++ )
                    for ( int t = 1 ; t <= 6 ; t++ )
                    {
                        if ( i==k && j == t ) continue;
                        if ( check(point[i][j] , point[k][t],
                                i , k ))
                            add ( i*6+j , k*6+t ,
                              dis( point[i][j] , point[k][t] ));   
                    }
        Point start,end;
        start.x = 0.0 , start.y = 5.0;
        end.x = 10.0 , end.y = 5.0;
        if ( check ( start , end , 0 , n+1 ) )
            add ( 1 , n*6+7 , 10.0 );
        for ( int i = 1 ; i <= n ; i++ )
            for ( int j = 1 ; j <= 6 ; j++ )
            {
                if ( check( start , point[i][j] ,0, i ) )
                    add ( 1 , i*6+j , dis ( start , point[i][j] ) );
                if ( check ( point[i][j], end , i , n+1 ) )
                    add ( i*6+j , n*6+7 , dis ( point[i][j] , end ) );
            }
        spfa ( );
       /* for ( int i = 1 ; i <= 6*n+7 ; i++ )
            printf ( "%lf " , way[i] );
        cout << endl;*/
       /* for ( int i = 0 ; i < cc ; i++ )
            cout << e[i].u<< "  " << e[i].v << "  " << e[i].w << endl;*/
        printf ( "%.2f\n" , way[n*6+7] );
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值