UVALive 7525 - Laser Game(最短路)

题目:传送门

思路:主要就是难在模型转换,只要看破,这道题就是很简单的最短路。s点t点以及每束光线的源点建立边,边的权值就是穿过这条边的光束数量。之后就是spfa跑一下s到t的最短路。在判断线段和射线相交的时候卡了很久。。。之前用一般式,连案例都跑不出,后来才想到斜率不存在的时候没有判断╮(╯▽╰)╭,然后直接换了参数方程写就不用判断斜率了。

下面是代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
#define N 210
#define INF 0x3f3f3f3f
#define LL long long
#define EPS 1e-8
using namespace std;

struct point{
    double x,y;
    point(){};
    point(double x,double y){
        this->x=x;
        this->y=y;
    }
};

struct line{
    point s,t;
    line(){};
    line(point s,point t){
        this->s=s;
        this->t=t;
    }
}l[205];

int n;
point s,t;
int g[N][N];
int dist[N];  
bool visit[N];  

double kross(point a,point b)
{
    return a.x*b.y-a.y*b.x;
}

bool pd(line a,line b)
{
    /*if(a.s.x==b.s.x&&a.s.y==b.s.y||a.t.x==b.s.x&&a.t.y==b.s.y)
        return false;*/
    point d1=point(a.t.x-a.s.x,a.t.y-a.s.y);
    //cout<<d1.x<<' '<<d1.y<<endl;
    point d2=point(b.t.x-b.s.x,b.t.y-b.s.y);
    //cout<<d2.x<<' '<<d2.y<<endl;
    point d3=point(a.s.x-b.s.x,a.s.y-b.s.y);
    //cout<<d3.x<<' '<<d3.y<<endl;
    double d1d2=kross(d2,d1);
    if(d1d2==0) return false;
    double k1=kross(d3,d2)/d1d2;
    double k2=kross(d3,d1)/d1d2;
    //cout<<k1<<' '<<k2<<endl;
    if(k1>0&&k1<1&&k2>0)
        return true;
    else
        return false; 
}

int get_points(point a,point b)
{
    int res=0;
    for(int i=1;i<=n;i++)
    {
        if(pd(line(a,b),l[i]))
            res++;
    }
    return res;
} 

void build_edge()
{
    for(int i=0;i<n+3;i++)
    {
        for(int j=0;j<n+3;j++)
            g[i][j]=INF;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            g[i][j]=g[j][i]=get_points(l[i].s,l[j].s);
        }
        g[n+1][i]=g[i][n+1]=get_points(s,l[i].s);
        g[n+2][i]=g[i][n+2]=get_points(t,l[i].s);
    }
    g[n+1][n+2]=g[n+2][n+1]=get_points(s,t);
}

void spfa(int start) {  
    queue<int> Q;  
    int i, now;  
    memset(visit, false, sizeof(visit));  
    for (i = 1; i <= n+2; i++){  
        dist[i] = INF;  
    }  

    dist[start] = 0;  
    Q.push(start);  
    visit[start] = true;  
    while (!Q.empty()) {  
        now = Q.front();  
        Q.pop();  
        visit[now] = false;  
        for (i = 1; i <= n+2; i++) {  
            if (dist[i] > dist[now] + g[now][i]) {  
                dist[i] = dist[now] + g[now][i];  
                if (visit[i] == 0) {  
                    Q.push(i);  
                    visit[i] = true;  
                }  
            }  
        }  
    }  
} 

int main()
{
    while(~scanf("%d",&n),n)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf",&l[i].s.x,&l[i].s.y,&l[i].t.x,&l[i].t.y);
        }
        scanf("%lf%lf%lf%lf",&s.x,&s.y,&t.x,&t.y);
        build_edge();
        //cout<<pd(line(l[2].s,t),l[3])<<endl;
        /*for(int i=1;i<=n+2;i++)
        {
            for(int j=1;j<=n+2;j++)
                cout<<g[i][j]<<' ';
            cout<<endl;
        }*/
        spfa(n+1);
        printf("%d\n",dist[n+2]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值