热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【poor几何】[UVALive6693]FlowGame计算几何,线代相交

【题目】Flowgameisapopulargamenowonsmartphoneduetotheinventionofmulti-touchscreen.

【题目】
Flow game is a p opular game now on smart phone due to the invention of multi-touch screen. The rule of the game is easy. Given a b oard with N × N grids and given a set of paired color dots, please find a way to connect paired color dots without crossing the paths of others as in Fig. 1.

Fortunately, the flow games you need to solve only have two pairs of color dots and the color dots only app ear on the lo cations of b oundary cells. For example, Fig. 2 shows the boundary cells in a 5 × 5 grids.

这里写图片描述

Once you connect two pairs of color dots, there is a cost for your solution. The cost of your solution is the numb er of painted cells (including two end dots). For example, in Fig. 1, blue line paints 7 cells and yellow line paints 5 cells. So, the total cost is 12 which is minimum in this game. Given an N × N grids, please output the minimum cost to connect the color dots.

这里写图片描述

Input
The test data b egins with a p ositive integer T, which is the number of test cases. Each test case begins with a positive integer N ( N <10), which is the size of the board. Following is N × N cells of board data. An empty cell is represented by a ‘ . ’. Color dots are described by ‘ 1’, ‘ 2’.

Output
Please output the minimum cost to connect the two pairs of dots. If there is no solution to a given game, please output ‘ -1’ in a new line.

Sample Input
2
5
.12..
…..
…..
1….
2….
5
.21..
…..
1….
2….
…..

Sample Output
12
-1

【题意】
给个棋盘,你可以在棋盘的边缘处放2个蓝色棋子2个黄色棋子,问连接2组同色棋子的最小代价,如果线路交叉,输-1。

【思路】
一般情况如果有解,则可发现两点连线最小代价=曼哈顿距离+1,所以一般情况:
ans=abs(X1-X2)+abs(Y1-Y2)+abs(X3-X4)+abs(Y3-Y4)+2;
判断-1:如果两个线段相交,则-1。
特例:
啊队友指出的特例,还发了个表情给我
这种情况下,ans则等于原来的ans+2,

关于判断两个线段相交,截取一段林厚从的计算几何讲义:

用叉积去做,分两步:

第 1 步:快速排斥试验,如果分别以 P1P2 , P3P4 为对角线做矩形,而这两个矩形不相交,则
这两条线段肯定不相交,如下左图;即使两个矩形相交,这两条线段也不一定相交,如下右图,
这时再用第 2 步判断;
这里写图片描述
表示成语句,即两个矩形相交当且仅当下列式子为真:
( max(x1,x2) ≥ min(x3,x4) )∧ (max(x3,x4) ≥ min(x1,x2)) ∧( max(y1,y2) ≥ min(y3,y4) )∧(max(y3,y4) ≥min(y1,y2))
两个矩形相交必须在两个方向上都相交,式子的前半部分判断在 x 方向上是否相交,后半部
分判断在 y 方向上是否相交。

第 2 步:确定每条线段是否“跨立”另一条线段所在的直线。
跨立:如果点 P1 处于直线 P3P4 的一边,而 P2 处于该直线的另一边,则我们说线段 p1 p2 跨
立直线 P3P4,如果 P1 或 P2 在直线 P3P4 上,也算跨立。
两条线段相交当且仅当它们能够通过第 1 步的快速排斥试验,并且每一条线段都跨立另一条
线段所在的直线。
这里写图片描述
具体第 2 步的实现,只要用叉积去做就可以了,即只要判断矢量 p1 p3 和 p1 p4 是否在 p1 p2
的两边相对的位置上,如果这样,则线段 p1 p2 跨立直线 P3P4。
也即检查叉积( P3-P1)×( P2-P1)与( P4-P1)×( P2-P1)的符号是否相同,相同则不跨立,线段也就不相交,否则相交。
当然也有一些特殊情况需要处理,如任何一个叉积为 0,则 P3 或 P4 在直线 P1P2 上,又因为
通过了快速排斥试验,所以下图左边的情况是不可能出现的,只会出现右边的两种情况。
当然,还会出现一条或两条线段的长度为 0,如果两条线段的长度都是 0,则只要通过快速排斥试验就能确定;如果仅有一条线段的长度为 0,如 p3 p4 的长度为 0,则线段相交当且仅当叉积( P3-P1)×( P2-P1)。
这里写图片描述

over

在本题中,判断相交的代码很好写,死套公式即可
对于3个跨立时的特例:
第一个:在矩形判断的时候就排除了,不用管
第二个:如果是斜的,依然有解,按一般情况判断
如果是横的或者竖的,则无解,这里要写几个if
(见代码中注释:跨立特判2)
第三个:和第二个一样,斜的不管,横的或竖的无解(跨立特判3)
还有一个fuck判断,就是队友指出的特例,这里输出ans+2
啊fuck

所以差不多了,,,贴代码?
代码十分恶心,密集恐惧症患者请备好速效救心丸。
几个点的坐标好烦,好多判断条件好烦,if特别多

【code】

#include
#include
#include
#include
using namespace std;
int T,n,i,j,x[5],y[5],A,ans;
int X1,X2,X3,X4,Y1,Y2,Y3,Y4;
char c[5],ch;
bool ok;
bool fuck(){//fuck就是之前那张带表情的特例 
    if (X1==X2&&X1==X3&&X1==X4){
        if ((Y1>min(Y3,Y4)&&(Y1min(Y3,Y4)&&(Y2return true;
        if ((Y3>min(Y1,Y2)&&(Y3min(Y1,Y2)&&(Y4return true;     
    }
    if (Y1==Y2&&Y1==Y3&&Y1==Y4){
        if ((X1>min(X3,X4)&&(X1min(X3,X4)&&(X2return true;
        if ((X3>min(X1,X2)&&(X3min(X1,X2)&&(X4return true;
    }
    return false;
}

bool kl(int x1,int y1,int x2,int y2,int x3,int y3){             //跨立
    int xy1=x1*y2-x2*y1;
    int xy2=x1*y3-x3*y1;
    return xy1*xy2<0;
}

bool xj(){//xj,显然就是相交的开头 
    if (X1==X2&&X1==X3&&X1==X4&&min(Y1,Y2)//跨立特判3 
        (Y4>max(Y1,Y2)||Y4return true;}
    if (Y1==Y2&&Y1==Y3&&Y1==Y4&&min(X1,X2)max(X1,X2)||X4return true;}

    if ((X1==X2)&&(X1==X3)&&(X1!=X4)&&(Y3min(Y1,Y2)))return true;//跨立特判2 
    if ((X1==X2)&&(X1==X4)&&(X1!=X3)&&(Y4min(Y1,Y2)))return true;
    if ((X3==X4)&&(X3==X1)&&(X3!=X2)&&(Y1min(Y3,Y4)))return true;
    if ((X3==X4)&&(X3==X2)&&(X3!=X1)&&(Y2min(Y3,Y4)))return true;
    if ((Y1==Y2)&&(Y1==Y3)&&(Y1!=Y4)&&(X3min(X1,X2)))return true;
    if ((Y1==Y2)&&(Y1==Y4)&&(Y1!=Y3)&&(X4min(X1,X2)))return true;
    if ((Y3==Y4)&&(Y3==Y1)&&(Y3!=Y2)&&(X1min(X3,X4)))return true;
    if ((Y3==Y4)&&(Y3==Y2)&&(Y3!=Y1)&&(X2min(X3,X4)))return true;

    if (max(X1,X2)<=min(X3,X4)) {return false;}                  //矩形相交 
    if (max(X3,X4)<=min(X1,X2)) {return false;}  
    if (max(Y1,Y2)<=min(Y3,Y4)) {return false;}  
    if (max(Y3,Y4)<=min(Y1,Y2)) {return false;}  
    if (!kl(X2-X1,Y2-Y1,X3-X1,Y3-Y1,X4-X1,Y4-Y1)) {return false;}  //跨立实验 
    if (!kl(X4-X3,Y4-Y3,X1-X3,Y1-Y3,X2-X3,Y2-Y3)) {return false;}  
    if (!kl(X3-X4,Y3-Y4,X1-X4,Y1-Y4,X2-X4,Y2-Y4)) {return false;}  
    if (!kl(X1-X2,Y1-Y2,X3-X2,Y3-Y2,X4-X2,Y4-Y2)) {return false;}  
    return true;
}

int main (){
    freopen("fuck.in","r",stdin);
    scanf("%d",&T);
    while (T--){
        scanf("%d%C",&n,&ch);
        A=0;
        for (i=1;i<=n;i++)
          for (j=1;j<=n;j++){
              cin>>ch;
              if (ch=='.')continue;
              x[++A]=i;y[A]=j;c[A]=ch;
              //printf("%d %d %c\n",i,j,ch);
          }
        //for (i=1;i<=4;i++)printf("%d %d %d %c\n",i,x[i],y[i],c[i]);
        ok=false;//这个取点感觉写的好挫,不过我还没想到更好的处理方案,先这么写吧
        for (i=1;i<4&&!ok;i++) for (j=i+1;j<=4&&!ok;j++)
          if ((c[i]=='1')&&(c[j]=='1'))
          {X1=x[i];Y1=y[i];X2=x[j];Y2=y[j];ok=true;break;}
        ok=false;
        for (i=1;i<4&&!ok;i++) for (j=i+1;j<=4&&!ok;j++)
          if ((c[i]=='2')&&(c[j]=='2'))
          {X3=x[i];Y3=y[i];X4=x[j];Y4=y[j];ok=true;break;}
        ans=abs(X1-X2)+abs(Y1-Y2)+abs(X3-X4)+abs(Y3-Y4)+2;
        //printf("%d %d %d %d\n%d %d %d %d\n",X1,Y1,X2,Y2,X3,Y3,X4,Y4);

        if (xj())printf("-1\n");
        else if (fuck())printf("%d\n",ans+2);
        else printf("%d\n",ans);
    }
    return 0;
} 

PS:本题似乎也可以用爆搜过掉(clairs爷就是这么干的),做两次bfs。
不过clairs爷说这套题有毒,,,= =
自己第一天写残了,第二天准备重写爆搜的时候复制第一天读入发现问题了(就是代码里感觉写的挫的一段),瞬间爆炸。。。


推荐阅读
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
author-avatar
会长大的幸福7007
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有