【CCCC】L3-018 森森美图 (30分),计算几何+判断三点共线+bfs最短路

简介: 【CCCC】L3-018 森森美图 (30分),计算几何+判断三点共线+bfs最短路

problem

L3-018 森森美图 (30分)
森森最近想让自己的朋友圈熠熠生辉,所以他决定自己写个美化照片的软件,并起名为森森美图。众所周知,在合照中美化自己的面部而不美化合照者的面部是让自己占据朋友圈高点的绝好方法,因此森森美图里当然得有这个功能。 这个功能的第一步是将自己的面部选中。森森首先计算出了一个图像中所有像素点与周围点的相似程度的分数,分数越低表示某个像素点越“像”一个轮廓边缘上的点。 森森认为,任意连续像素点的得分之和越低,表示它们组成的曲线和轮廓边缘的重合程度越高。为了选择出一个完整的面部,森森决定让用户选择面部上的两个像素点A和B,则连接这两个点的直线就将图像分为两部分,然后在这两部分中分别寻找一条从A到B且与轮廓重合程度最高的曲线,就可以拼出用户的面部了。 然而森森计算出来得分矩阵后,突然发现自己不知道怎么找到这两条曲线了,你能帮森森当上朋友圈的小王子吗?

为了解题方便,我们做出以下补充说明:

图像的左上角是坐标原点(0,0),我们假设所有像素按矩阵格式排列,其坐标均为非负整数(即横轴向右为正,纵轴向下为正)。
忽略正好位于连接A和B的直线(注意不是线段)上的像素点,即不认为这部分像素点在任何一个划分部分上,因此曲线也不能经过这部分像素点。
曲线是八连通的(即任一像素点可与其周围的8个像素连通),但为了计算准确,某像素连接对角相邻的斜向像素时,得分额外增加两个像素分数和的√
​2

​​ 倍减一。例如样例中,经过坐标为(3,1)和(4,2)的两个像素点的曲线,其得分应该是这两个像素点的分数和(2+2),再加上额外的(2+2)乘以(√
​2

​​ −1),即约为5.66。
输入格式:
输入在第一行给出两个正整数N和M(5≤N,M≤100),表示像素得分矩阵的行数和列数。

接下来N行,每行M个不大于1000的非负整数,即为像素点的分值。

最后一行给出用户选择的起始和结束像素点的坐标(X
​start
​​ ,Y
​start
​​ )和(X
​end
​​ ,Y
​end
​​ )。4个整数用空格分隔。

输出格式:
在一行中输出划分图片后找到的轮廓曲线的得分和,保留小数点后两位。注意起点和终点的得分不要重复计算。

输入样例:
6 6
9 0 1 9 9 9
9 9 1 2 2 9
9 9 2 0 2 9
9 9 1 1 2 9
9 9 3 3 1 1
9 9 9 9 9 9
2 1 5 4
输出样例:
27.04

  • 给出一个n*m的矩阵,每个点有点权
  • 求两条分散在起点s到终点t连线两边的最短点权路(可以用斜边),输出权值和

solution

  • 将矩形分成ab两边分别求最短路,转移的时候用三点共线判断是否越界即可。
  • 矩形上求最短路可以直接bfs,当然dijkstra或者spfa也区别不大。
#include<bits/stdc++.h>
using namespace std;
const int inf = 1e9+10;
const int maxn = 110;

struct point{ int x, y;  double dis;};
bool operator!=(point a, point b){return a.x!=b.x||a.y!=b.y;}
bool operator==(point a, point b){return a.x==b.x&&a.y==b.y;}

int n, m;
double sc[maxn][maxn];//分数
point s, t;
void input(){
    cin>>n>>m;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            cin>>sc[i][j];
    cin>>s.y>>s.x>>t.y>>t.x;
    s.x++;s.y++;t.x++;t.y++;
    s.dis = sc[s.x][s.y];
}

int flag;//1上半部分,0下半部分
double f[maxn][maxn]; //到i,j为止的最小值
int dir[][2]= {{0,1},{1,0},{-1,0},{0,-1},{-1,-1},{1,-1},{-1,1},{1,1}}; //上下左右+前后左右
int cross(point a,point b,point p){//三角形行列式公式,判断三点是否在一个直线上
    return (b.x-a.x)*(p.y-a.y)-(p.x-a.x)*(b.y-a.y);
}
bool check(point p){//检查p是否合法(越界)
    if(p.x<1||p.x>n||p.y<1||p.y>m)return false;//越界
    if(flag && p!=s&&p!=t && cross(s,t,p)<=0)return false;//1:上半部分但点在下面(起点终点不算)
    if(!flag && p!=s&&p!=t && cross(s,t,p)>=0)return false;//2.下半部分但点在上面
    if(p.dis>=f[p.x][p.y])return false;//不是最小值
    return true;
}
void bfs(){
    //init
    queue<point>q;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            f[i][j] = inf;
    //search
    if(check(s)){
        f[s.x][s.y] = s.dis;
        q.push(s);
    }
    while(q.size()){
        point now = q.front(); q.pop();
        point next;
        for(int i = 0; i < 8; i++){
            next.x=now.x+dir[i][0];
            next.y=now.y+dir[i][1];
            if(i<4)next.dis = f[now.x][now.y]+sc[next.x][next.y];
            else next.dis=f[now.x][now.y]+sc[next.x][next.y]+(sc[next.x][next.y]+sc[now.x][now.y])*(sqrt(2)-1);
            if(check(next)){
                f[next.x][next.y] = next.dis;
                q.push(next);
            }
        }
    }
}

int main(){
    input();
    double ans = 0;
    flag = 1; bfs(); ans += f[t.x][t.y];//搜上面
    flag = 0; bfs(); ans += f[t.x][t.y];//搜下面
    ans -= sc[s.x][s.y]+sc[t.x][t.y];//重复
    printf("%.2f\n",ans);
    return 0;
}
目录
相关文章
|
编解码 人工智能 物联网
少年侠客【InsCode Stable Diffusion美图活动一期】
lnscode提供了学习和使用Stable Diffusion的环境,已经安装了相关软件和组件库,可直接启动Stable Diffusion WebUI进行创作
222 1
|
定位技术
【CCCC】L3-007 天梯地图 (30分),两次Dijkstra+路径打印(数据点2,4错因),90行最短题解
【CCCC】L3-007 天梯地图 (30分),两次Dijkstra+路径打印(数据点2,4错因),90行最短题解
304 0
|
Docker 容器
Docker服务启动失败报错:Job for docker.service failed because the control process exited with error code.
Docker服务启动失败报错:Job for docker.service failed because the control process exited with error code.
技术经验分享:HLG1314火影忍者之~纲手
技术经验分享:HLG1314火影忍者之~纲手
596 0
|
存储 定位技术
【天梯赛】L2-048 寻宝图 (DFS做法)
遇到一个非'0'字符(也就是'1'和 宝藏'2'到'9')就让ans++,同时将这个非'0'字符染色为'0',然后往四个方向(上、下、左、右)搜索,这里的目的是那一片岛屿(也就是那一片为'1'的部分)都染色为‘0’。本题就请你统计一下,给定的地图上一共有多少岛屿,其中有多少是有宝藏的岛屿。为了判断有宝藏的岛屿,这里我开了一个全局变量f来判断这一片岛屿是否有宝藏(也就是有无字符'2'-'9'),当搜到字符'2'~'9'时就将f标记为1。在一行中输出 2 个整数,分别是岛屿的总数量和有宝藏的岛屿的数量。
302 5
|
C++
【天梯赛】L1-094 剪切粘贴
创建一个简单的文本编辑器,实现剪切和粘贴功能。给定初始字符串S和操作次数N,根据输入的剪切位置和插入位置信息,执行相应操作。每次剪切会将指定部分放入剪贴板并从当前字符串中删除,粘贴则在找到合适位置插入剪贴板内容并清空剪贴板。最后输出操作后的字符串。提供的C++代码通过读取输入,使用string的substr、erase和insert方法来模拟剪切和粘贴操作。
183 2
|
存储 人工智能 C++
【PTA】L1-064 估值一亿的AI核心代码(详C++)
【PTA】L1-064 估值一亿的AI核心代码(详C++)
368 1
|
机器学习/深度学习 人工智能 物联网
基于YOLOv8深度学习的苹果叶片病害智能诊断系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战
基于YOLOv8深度学习的苹果叶片病害智能诊断系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战
|
算法 测试技术 C语言
从C语言到C++_24(二叉搜索树)概念+完整代码实现+笔试题(上)
从C语言到C++_24(二叉搜索树)概念+完整代码实现+笔试题
168 0
|
人工智能 安全 BI
L2-038 病毒溯源 (25 分)(dfs)
L2-038 病毒溯源 (25 分)(dfs)
562 0
L2-038 病毒溯源 (25 分)(dfs)