POJ 1556 The Doors【单源最短+线段相交】

35 篇文章 0 订阅
9 篇文章 0 订阅


点击打开链接


题意:

给你一个10*10的方格, 然后在里面放不超过十堵墙。然后问你从 (0,5)->(10,5)的最短路。


题解:

最短路,但是建图非常恶心,需要判断线段之间是否相交。不相交才能建边。



判断两线段是否相交。模板

double mult(Point a, Point b, Point c)  
{  
    return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);  
}  
  
//aa, bb为一条线段两端点 cc, dd为另一条线段的两端点 相交返回true, 不相交返回false  
bool intersect(Point aa, Point bb, Point cc, Point dd)  
{  
    if ( max(aa.x, bb.x)<min(cc.x, dd.x) )  
    {  
        return false;  
    }  
    if ( max(aa.y, bb.y)<min(cc.y, dd.y) )  
    {  
        return false;  
    }  
    if ( max(cc.x, dd.x)<min(aa.x, bb.x) )  
    {  
        return false;  
    }  
    if ( max(cc.y, dd.y)<min(aa.y, bb.y) )  
    {  
        return false;  
    }  
    if ( mult(cc, bb, aa)*mult(bb, dd, aa)<0 )  
    {  
        return false;  
    }  
    if ( mult(aa, dd, cc)*mult(dd, bb, cc)<0 )  
    {  
        return false;  
    }  
    return true;  
}  

之后就是跑一边spfa。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <math.h>
#include <queue>
#include <map>
using namespace std;
#define inf 0x7ffffff
map<pair<double,double>,int>m;
pair<double ,double>p1,p2,a[155];
pair<pair<double,double>,pair<double,double> >wall[55];

int n,cnt,nn,cnt2;
double mult(pair<double,double>a0,pair<double,double>a1,pair<double,double>a2){
    return (a0.first-a2.first)*(a1.second-a2.second)-(a1.first-a2.first)*(a0.second-a2.second);
}
int judge(pair<double,double>a0,pair<double,double>a1,pair<double,double>a2,pair<double,double>a3){
    if ( max(a0.first, a1.first)<=min(a2.first, a3.first) )   return false;
    if ( max(a0.second, a1.second)<=min(a2.second, a3.second) )  return false;
    if ( max(a2.first, a3.first)<=min(a0.first, a1.first) )  return false;
    if ( max(a2.second, a3.second)<=min(a0.second, a1.second) )  return false;
    if ( mult(a2, a1, a0)*mult(a1, a3, a0)<=0 )  return false;
    if ( mult(a0, a3, a2)*mult(a3, a1, a2)<=0 )  return false;
    return true;
}
struct Edge{
    int v;
    double w;
    Edge(int _v=0,double _w=0):v(_v),w(_w){}
};
double get_d(pair<double,double>x,pair<double,double>y){
    return sqrt((x.first-y.first)*(x.first-y.first)+(x.second-y.second)*(x.second-y.second));
}
vector<Edge>e[55*55];
void addedge(int u,int v,double w){
    e[u].push_back(Edge(v,w));
}
int vis[111];
double dis[111];
void spfa(){
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=cnt;++i) dis[i]=inf;
    vis[1]=1;
    dis[1]=0;
    queue<int>que;
    while(!que.empty())que.pop();
    que.push(1);
    while(!que.empty()){
        int u=que.front();
        que.pop();
        vis[u]=0;
        for(int i=0;i<e[u].size();++i){
            int v=e[u][i].v;
            if(dis[v]>dis[u]+e[u][i].w){
                dis[v]=dis[u]+e[u][i].w;
                if(!vis[v]){
                    vis[v]=1;
                    que.push(v);
                }
            }
        }
    }
}
int main(){
    double b,mm;
    while(scanf("%d",&n)){
       if(n==-1) break;
       for(int i=0;i<100;++i) e[i].clear();
       cnt=0,nn=2,cnt2=0;
       a[++cnt].first=0,a[cnt].second=5;m[a[cnt]]=cnt;
       a[++cnt].first=10,a[cnt].second=5;m[a[cnt]]=cnt;
       int T=n;
       while(T--){
           scanf("%lf",&mm);
           for(int i=1;i<=4;++i){
                scanf("%lf",&b);
                a[++cnt].first=mm,a[cnt].second=b;m[a[cnt]]=cnt;
           }
           p1.first=mm,p1.second=0,p2.first=mm,p2.second=10;
           wall[++cnt2].first=p1,wall[cnt2].second=a[nn+1];
           wall[++cnt2].first=a[nn+2],wall[cnt2].second=a[nn+3];
           wall[++cnt2].first=a[nn+4],wall[cnt2].second=p2;
           nn=cnt;
       }
       for(int i=1;i<=cnt;++i){
            for(int j=i+1;j<=cnt;++j){
                int f=1;
                for(int k=1;k<=cnt2;++k)
                    if(judge(a[i],a[j],wall[k].first,wall[k].second)){
                    f=0;break;
                    }
                if(f){
                    double t=get_d(a[i],a[j]);
                    addedge(m[a[i]],m[a[j]],t);
                    addedge(m[a[j]],m[a[i]],t);
                }
            }
       }
       spfa();
       printf("%.2f\n",dis[2]);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值