题目链接:[CodeForces498A]Crazy Town[几何][附简略证明]
题意分析:n条直线将地图切成多个块,起点终点都在块上,问从起点到终点,最少要走多少步?(有公共边的块认为是相邻的块)
解题思路:猜想:A、B两点间的线段与多少条直线相交,就是我们需要走的步数。即:步数 = 与线段相交的直线条数(直接搜题解的朋友,建议看到这里就自己去实现一方,或者自己去证明下)
简略证明:
首先,交点在线段以外的话,相当于把整个地图的边界变小了,对步数没有影响。
其次,考虑交点在线段上,其中最简单的一种情况(1):
这时中间两条直线将其划分为三个域。
接着我们移动一下直线,有(2):
注意到,当两条线相交后,相当于原来在上面的a线,变成了下面的b线,两条线的切割位置互换了,对于整个最小距离是没有影响的。所以只用考虑交点数即可判断最小步数了。过线段的直线的相交,平行是不影响最终结果的。
证毕。
个人感受:上个学期遇到的题,一点思路都没有。昨天又见到,就大胆猜想了下。说到与AB线段的交点,我昨天第一次是直接求出交点,然后判断有多少个交点在A、B的坐标域内。结果WA36,23333。然后经舍友提醒,原来还有线性规划这档子事,唉呀呀~
具体代码如下:
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
#include <set>
#include <algorithm>
typedef long long ll;
using namespace std;
const double eps = 1e-7;
int main() {
double x1, x2, y1, y2;
cin >> x1 >> y1 >> x2 >> y2;
int ans = 0;
int n; cin >> n;
for (int i = 0; i < n; ++i)
{
double a, b, c;
cin >> a >> b >> c;
if ((a * x1 + b * y1 + c)*(a * x2 + b * y2 + c) < eps) //线性规划:当两点在直线两端时,带入两点,乘积必定是负数
++ans;
}
cout << ans << '\n';
return 0;
}