270 - Lining Up UVA


``How am I ever going to solve this problem?" said the pilot.

Indeed, the pilot was not facing an easy task. She had to drop packages at specific points scattered in a dangerous area. Furthermore, the pilot could only fly over the area once in a straight line, and she had to fly over as many points as possible. All points were given by means of integer coordinates in a two-dimensional space. The pilot wanted to know the largest number of points from the given set that all lie on one line. Can you write a program that calculates this number?

Your program has to be efficient!

Input

The input begins with a single positive integer on a line by itself indicating the number of the cases following, each of them as described below. This line is followed by a blank line, and there is also a blank line between two consecutive inputs.
The input consists of N pairs of integers, where 1 < N < 700. Each pair of integers is separated by one blank and ended by a new-line character. The list of pairs is ended with an end-of-file character. No pair will occur twice.

Output

For each test case, the output must follow the description below. The outputs of two consecutive cases will be separated by a blank line. 
The output consists of one integer representing the largest number of points that all lie on one line.

Sample Input

1

1 1
2 2
3 3
9 10
10 11

Sample Output

3
 
备份:RuntimeError
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
using namespace std;
const int maxn = 10;
struct point
{
    double x;
    double y;
}p[1000000];
double k[1000000];
char b[1000000];
int vis[1000000];
int main()
{
    memset(vis,0,sizeof(vis));
    int n;
    scanf("%d",&n);
    int i;
    for(i = 0;i<n;++i)
    {
        printf("\n");
        int t = 0;
        int j;
        int a=0;
        int count = 1;
        while(gets(b))
        {
            if(!strlen(b))
                break;
            sscanf(b,"%lf %lf",&p[t].x,&p[t].y);
            //int count = 1;
            if(t!=0)
            for(int q = t;q>=1;--q)
            {
            ++a;
            if((p[t].x-p[q-1].x) == 0)
            //k[a] = 0;
            count++;
            else
            k[a] =(double) (p[t].y -p[q-1].y)/(p[t].x-p[q-1].x);
            }
            t++;
        }
        int maxp = 1;
        if(a!=0)
        {
        for(j = 1;j<=a&&vis[j]==0;++j)
        {
           int sum=1;
           for(int m = j+1;m<=a;++m)
           {
               if(fabs(k[j]-k[m])<1e-6&&vis[m]==0)
               {
                     sum++;
                     vis[m]=1;
               }
           }
           maxp = max(sum,maxp);
        }
        maxp = max(maxp,count);
        int A = 0;
        for(j = 1;j<710;++j)
        {
            A+=j;
            if(A==maxp)
            {
                printf("%d\n",j+1);
                break;
            }
        }
        }
        }
    return 0;
}




参考:http://www.cnblogs.com/staginner/archive/2011/12/30/2307831.html

这个题目我只想到了优化常数的办法,没想到AC了,但耗时还是不容乐观的,这个题好像是有n^2logn的算法,要先进行排序再处理,但暂时还没有找到相应的详细一点的思路。

    优化常数的办法就是用一个邻接矩阵记录一下哪两个点以前已经在某条直线上被算过了,那么在枚举的时候就不用再枚举这两个点作为一条直线了。

    后来又琢磨了一下看到的那句“按极角排序”的话,恍然大悟了,实际就是把枚举的过程由枚举两个点变成枚举一个点,之后以这个点为原点,将其余所有点按和这个点连线的斜率的大小进行排序,然后去计算每条射线上点的数目(这样是不会丢解的,因为我们枚举了所有点作为原点,必然也就枚举了可能的直线的端点,而这时直线就相当于射线了),而计算的过程是可以在O(n)的时间内完成的,排序的时间是O(nlogn),枚举的基本时间是O(n),所以总的复杂度就约是O(n^2logn)。

#include<stdio.h>
#include<string.h>
#define MAXD 710
int g[MAXD][MAXD], s[MAXD], N, x[MAXD], y[MAXD], max;
char b[110];
void init()
{
    N = 0;
    while(gets(b) != NULL)
    {
        if(b[0] == '\0')
            break;
        sscanf(b, "%d%d", &x[N], &y[N]);
        ++ N;
    }
}
void solve()
{
    int i, j, k, p, q, top;
    memset(g, -1, sizeof(g));
    max = 0;
    for(i = 0; i < N; i ++)
        for(j = i + 1; j < N; j ++)
            if(g[i][j])
            {
                top = 0;
                for(k = 0; k < N; k ++)
                    if((y[j] - y[i]) * (x[k] - x[i]) == (x[j] - x[i]) * (y[k] - y[i]))
                        s[top ++] = k;
                if(top > max)
                    max = top;
                for(p = 0; p < top; p ++)
                    for(q = p + 1; q < top; q ++)
                        g[s[p]][s[q]] = g[s[q]][s[p]] = 0;
            }
    printf("%d\n", max);
}
int main()
{
    int t, tt;
    gets(b);
    sscanf(b, "%d", &t);
    gets(b);
    for(tt = 0; tt < t; tt ++)
    {
        init();
        if(tt)
            printf("\n");
        solve();
    }
    return 0;
}


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXD 710
int r[MAXD], N, M, x[MAXD], y[MAXD], max, C;
char b[110];
int cmp(const void *_p, const void *_q)
{
    int *p = (int *)_p;
    int *q = (int *)_q;
    int ans = (y[*p] - y[C]) * (x[*q] - x[C]) - (y[*q] - y[C]) * (x[*p] - x[C]);
    if(x[*q] - x[C] < 0)
        ans = -ans;
    if(x[*p] - x[C] < 0)
        ans = -ans;
    return ans;
}
void init()
{
    N = 0;
    while(gets(b) != NULL)
    {
        if(b[0] == '\0')
            break;
        sscanf(b, "%d%d", &x[N], &y[N]);
        ++ N;
    }
}
void solve()
{
    int i, j, k, p, q;
    max = 2;
    for(i = 0; i < N; i ++)
    {
        M = 0;
        for(j = 0; j < N; j ++)
            if(x[j] != x[i])
                r[M ++] = j;
        if(N - M > max)
            max = N - M;
        C = i;
        qsort(r, M, sizeof(r[0]), cmp);
        for(j = 1, k = 2; j < M; j ++)
        {
            p = r[j - 1], q = r[j];
            if((y[p] - y[i]) * (x[q] - x[i]) == (y[q] - y[i]) * (x[p] - x[i]))
                ++ k;
            else
            {
                if(k > max)
                    max = k;
                k = 2;
            }
        }
        if(k > max)
            max = k;
    }
    printf("%d\n", max);
}
int main()
{
    int t, tt;
    gets(b);
    sscanf(b, "%d", &t);
    gets(b);
    for(tt = 0; tt < t; tt ++)
    {
        init();
        if(tt)
            printf("\n");
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值