USACO Training Section 3.4 Electric Fence

[url="http://ace.delos.com/usacoprob2?a=63jK4mxxm0s&S=fence9"]英文原题[/url]

大意:给定一个三角形(0,0),(m,n),(p,0)求三角形内部的整数格点的数量。

可以用皮克定理求解:给定任意简单多边形,其面积A和内部格点数目i、边上格点数目b的关系:A = i + b/2 - 1。 而线段<(0,0),(n,m)>上的格点数(包含端点)等于n与m的最大公约数+1,从而对多边形而言,边上的格点数总和为边向量的xy分量最大公约数之和(去掉重复计数)。多边形面积为点积和。从而得解。

这里的实现包含了对一般简单多边形的处理。

对这个题而言,还可以参考图形学中的划线算法,对每行得到内部格点的最大最小值,求和得到解。

有意思的是,中文题译与英文原题完全不同,同一个题目名字,内容不同,是较早的电网版本,比这个题要困难一些,摘录如下:

农夫约翰已经决定建造电网。他已经把他的农田围成一些奇怪的形状,现在必须找出安放电源的最佳位置。

对于段电网都必须从电源拉出一条电线。电线可以穿过其他电网或者跨过其他电线。电线能够以任意角度铺设,从电源连接到一段电网的任意一点上(也就是,这段电网的端点上或者在其之间的任意一点上)。这里所说的“一段电网”指的是呈一条线段状的电网,并不是连在一起的几段电网。若几段电网连在一起,那么也要分别给这些电网提供电力。

已知所有的 F(1 <= F <= 150)段电网的位置(电网总是和坐标轴平行,并且端点的坐标总是整数,0 <= X,Y <= 100)。你的程序要计算连接电源和每段电网所需的电线的最小总长度,还有电源的最佳坐标。

电源的最佳坐标可能在农夫约翰的农田中的任何一个位置,并不一是整数。

这是个平面极值问题,如果用解析方法求解,电网的xy坐标将目标区域划分成的网格,网格中每个区域的方程是不同的,需在每个区域内求得极值并最终得到解。不过从编程角度看,用四分法求解就足够了。


/*
ID: blackco3
TASK: fence9
LANG: C++
*/
#include <iostream>
using namespace std;
const int _n_pt_(3) ;
struct t_point {
int x, y ;
t_point(int a=0, int b=0):x(a),y(b){};
} ;
inline int iabs(int v) {
return v<0 ? -v : v ;
}
inline int cross(t_point const &a, t_point const &b){
return a.x*b.y - a.y*b.x;
}
inline int gcd(int a, int b) {
while(a && b)
a %= b , b = a ? b%a : b ;
return a + b ;
}
inline int grids_on_line(t_point const &a, t_point const &b) {
return gcd( iabs(a.x-b.x), iabs(a.y-b.y) ) ;
}

int poly_area(t_point *poly, int n_size) {
int area=0 ;
for(int i=0; i<n_size; i++) {
area += cross( poly[i], poly[i+1] );
}
return iabs(area)/2;
}

int Pick_grid(t_point *poly, int n_size ) {
int sum_bound=0 ;
for(int i=0; i<n_size; i++ )
sum_bound += grids_on_line(poly[i], poly[i+1]);
return poly_area(poly, n_size) - (sum_bound>>1) + 1;
}

int main() {
freopen("fence9.in", "r", stdin);
freopen("fence9.out","w",stdout);
t_point poly[_n_pt_+1] ;
cin >> poly[1].x >> poly[1].y >> poly[2].x;
cout << Pick_grid(poly, _n_pt_) << endl;
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值