ZOJ 3400 Treasure Hunting


 Treasure Hunting


Time Limit: 2 Seconds      Memory Limit: 65536 KB

Suffered from the economic crisis, the government has a great deficit, so they decide to exploit a treasure area.

In this area, each lattice point has one unit of treasure, and the government plans to build upN tunnels, which will start from one lattice point and end at another lattice point. As the tunnel pass a lattice point, that unit of treasure will be obtained by the government. Unfortunately, because of the poor plan, the tunnels may overlap or intersect with each other. However, even if multiple tunnels intersect at a grid point, the government can get only 1 unit of treasure at each of these intersections.

According to the plan, the government wants to know how much treasure they can get in advance.

Input

There're multiple test cases (no more than 20).

The first line of each test case contains an integer N (1 <= N <= 1000), indicating the number of tunnels.

The following N lines contain four integer x1, y1, x2 andy2(|x1 -x2| + |y1 -y2| > 0), represents the starting and ending points of theith tunnel.The absolute value of x1, y1, x2 andy2 will no larger than 1000000.

Output
Output the quantity of the treasure the government will get.
Sample Input
6
0 0 2 4
0 0 4 2
2 0 2 4
3 0 0 3
2 4 5 5
4 2 5 5
Sample Output
11
Hint

The chart of the sample:


这是无意中看别人的博客时发现的一道题....题意就是:1000条线段,覆盖了多少了整数格子点,坐标范围1000000.....

坐标范围很大.无法下手,因此很容易想到从 1000下手...对一条线段来说,我们可以得到它能够覆盖的整数点..多条线段产生的问题就是有重复的,,

如何解决呢?果断n^2枚举看交点,记录这些产生的交点,,如果一个点有K条线段经过,那么在n^2的枚举过程中会产生A(k,2)个相同的交点,通过得到相同交点的数目,很容易计算出经过该点的线段数K,然后减去(  K-1)就去重了...在这个过程中,会发现当两线段重叠一部分时,它的交点数目会很多,如果不采取措施,必然会T....因此对于这种情况,我们首先对线段进行合并,然后再求交,我挂了一天多:合并前先排个序,不然会出现合并不彻底的情况

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define Abs(x)(((x)<0?(-(x)):(x)))
using namespace std;
long long gcd(long long a,long long b)
{
    if(b==0)return a;
    else return gcd(b,a%b);
}
struct P
{
    long long x,y;
    void read(){cin>>x>>y;}
    P(){}
    P(long long x,long long y):x(x),y(y){}
    long long operator *(const P& b){return x*b.y-y*b.x;}
    P operator *(double d){return P(x*d,y*d);}
    P operator /(double d){return P(x/d,y/d);}
    P operator -(const P& b){return P(x-b.x,y-b.y);}
    P operator +(const P& b){return P(x+b.x,y+b.y);}
    bool operator <=(const P& tmp)const
    {
       if(x!=tmp.x)return x<tmp.x;
       else return y<=tmp.y;
    }
	bool operator <(const P& tmp)const
    {
       if(x!=tmp.x)return x<tmp.x;
       else return y<tmp.y;
    }
    bool operator ==(const P& tmp)const{return x==tmp.x&&y==tmp.y;}
    void out(){cout<<x<<" "<<y<<" ,";}
}r[500005];
struct Line
{
    P a,b;
    long long K;
    void read()
    {
        a.read();b.read();
        if(b<=a)swap(a,b);
    }
    void out()
    {
        puts("LINE");
        a.out(),b.out();puts("");
    }
    void calc()
    {
        K=gcd(Abs(b.x-a.x),Abs(b.y-a.y))+1;
    }
}L[1005];
bool vis[1005];
int cnt;
P min(const P& p1,const P& p2) {	return p1<=p2?p1:p2;	}
P max(const P& p1,const P& p2) {	return p1<=p2?p2:p1;	}
long long xmult(P p1,P p2,P p3){	return (p3-p1)*(p2-p1);	}
bool ins_seg(Line &L1, Line L2)
{
    if(xmult(L1.a,L1.b,L2.a)==0&&xmult(L1.a,L1.b,L2.b)==0)
    {
	    if(L2.b<L1.a||L1.b<L2.a)return false;
		L1.a=min(L1.a,L2.a);
		L1.b=max(L1.b,L2.b);
		return true;
    }
    return false;
}
bool cmp(const P& p1,const P& p2){	return p1<p2;	}
bool cmp_Line(const Line& p1,const Line& p2)
{
    return p1.a<p2.a||p1.a==p2.a&&p1.b<p2.b;
}
void ins_seg_P(Line L1,Line L2)
{
    long long u,v;
    u=(L1.b-L1.a)*(L2.a-L1.a);
    v=(L1.a-L1.b)*(L2.b-L1.b);
    P res=L2.a*v+L2.b*u;
    if(u+v==0)return;
    if(res.x%(u+v)!=0)return;
    if(res.y%(u+v)!=0)return;
    res.x/=(u+v);res.y/=(u+v);
    if(L1.a<=res&&res<=L1.b&&L2.a<=res&&res<=L2.b)
		r[++cnt]=res;
}
int main()
{
    freopen("a.in","r",stdin);
    int n;
    while(~scanf("%d",&n))
    {
        int res=0;
        for(int i=1;i<=n;i++)L[i].read();

        sort(L+1,L+n+1,cmp_Line);

        memset(vis,0,sizeof(vis));

        for(int i=1;i<=n;i++)
        if(!vis[i])
        {
            for(int j=i+1;j<=n;j++)
            if(!vis[j])
            {
				vis[j] = ins_seg(L[i],L[j]);
            }
            L[i].calc();
            res+=L[i].K;
        }
        cnt=0;
        for(int i=1;i<=n;i++)
        if(!vis[i])
        for(int j=i+1;j<=n;j++)
        if(!vis[j])
        {
            ins_seg_P(L[i],L[j]);
        }
        sort(r+1,r+cnt+1,cmp);
        int st,ed;
        st=1;
		while(st<=cnt)
        {
            ed=st;
            while(ed<cnt&&r[st]==r[ed+1])ed++;
            res-=(int)( sqrt((ed-st+1)*2) );
            st=ed+1;
        }
        printf("%d\n",res);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值