zoukankan      html  css  js  c++  java
  • 天梯赛 森森美图

    https://pintia.cn/problem-sets/994805046380707840/problems/994805047395729408

    先说一下题意

    在一个二维点阵上选两个点s、t,这两个点所在的直线将这个点阵分成两部分

    在这两部分里面分别找一条s到t的路径(八连通),这两条路径构成一个闭环,最小化闭环的分数

    注意直线所经过的点不属于任何一部分,不能使用

    闭环的分数定义为:

    每个点都有一个分数,将闭环上的点的分数相加

    同时,如果两个点是斜着连通的,那还需要额外加上这两个点分数和的(根号2-1)倍

    踩的坑:

    1、点的坐标是从0开始计算的

    2、向右为x轴,向下为y轴,即给出的点的坐标第一个是列坐标,第二个是行坐标

    3、如果路径连续斜着经过的点有3个或更多个,是所有斜着相邻连通的点对都有额外的加分,也就是中间斜着的会计算2次额外加分

    这就是在每一个部分做一次spfa

    如何判断下一个点v是否在该部分:利用叉积

    x到s看作是一个向量,x到t看作是一个向量

    两个向量做叉积

    所有叉积<0的是一部分,所有叉积>0的是一部分,所有叉积=0的不属于任何一部分

    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    #define N 101
     
    int n,m; 
    int mp[N][N];
    
    int sx,sy,tx,ty;
    double pp;
    
    struct node
    {
        int x,y;
    };
    
    int dx[8]={-1,1,0,0,-1,-1,1,1}; //上、下、左、右、左上、右上、左下、右下 
    int dy[8]={0,0,-1,1,-1,1,-1,1};
    
    double d[N][N];
    bool vis[N][N];
    
    int tty; 
    double ans;
    
    bool judge(int x,int y) //叉积判断是否属于同一部分 
    {
        int a1=sx-x,b1=sy-y;
        int a2=tx-x,b2=ty-y;
        if(tty==1) return (a1*b2-b1*a2<0);
        else return (a1*b2-b1*a2>0);
    }
    
    void bfs()
    {
        pp=sqrt(2)-1;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
                d[i][j]=2e9; 
        queue<node>q;
        node now,nxt;
        now.x=sx;
        now.y=sy;
        d[sx][sy]=mp[sx][sy];
        vis[sx][sy]=true;
        q.push(now);
        int nx,ny;
        double nd;
        while(!q.empty())
        {
            now=q.front();
            q.pop();
            vis[now.x][now.y]=false;
            for(int i=0;i<8;++i)
            {
                nx=now.x+dx[i];
                ny=now.y+dy[i];
                if(nx<1 || nx>n || ny<1 || ny>m) continue;
                if(!judge(nx,ny) && (nx!=tx || ny!=ty)) continue;
                nd=d[now.x][now.y]+mp[nx][ny];
                if(i>=4) nd+=(mp[nx][ny]+mp[now.x][now.y])*pp; //斜着额外的分数 
                if(nd<d[nx][ny])
                {
                    d[nx][ny]=nd;
                    if(nx==tx && ny==ty) continue;
                    if(!vis[nx][ny])
                    {
                        nxt.x=nx;
                        nxt.y=ny;
                        q.push(nxt);
                        vis[nx][ny]=true;
                    }
                }
            }
        }
        ans+=d[tx][ty]; 
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j) 
                scanf("%d",&mp[i][j]);
        scanf("%d%d%d%d",&sy,&sx,&ty,&tx);
        sy++;
        sx++;
        ty++;
        tx++;
        tty=1; //标记现在是做哪一部分
        bfs();
        tty=2;//标记现在是做哪一部分
        bfs();
        printf("%.2lf",ans-mp[sx][sy]-mp[tx][ty]); //起始位置算了2次 
    }
  • 相关阅读:
    iis6 , URL重写HTM文件名后,出现真实的HTM文件不能访问的解决
    pe如何安装ios系统
    ASP.NET Word转为PDF
    asp.net 操作word 权限
    windows server 2008 r2 修改远程登入的端口号(3389)
    A
    A Bug
    亲戚
    Kruskal
    HDOJ ——统计难题
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/13769969.html
Copyright © 2011-2022 走看看