sgu128

来源:互联网 发布:sql server 2008 补丁 编辑:程序博客网 时间:2024/06/06 01:14

题目:

128. Snake

time limit per test: 0.25 sec. 
memory limit per test: 4096 KB

There are N points given by their coordinates on a plane. All coordinates (xi,yi) are integers in a range from -10000 up to 10000 inclusive . It is necessary to construct a broken line satisfying the following conditions:
1. The broken line should be closed.
2. End points of each segment (verteces) of the broken line can only be the given points, and all given points should be used.
3. Each two consecutive segments of the broken line should form a corner of 90 degrees in each vertex point.
4. The sides of the broken line should be parallel to coordinate axes.
5. The broken line should have no self-crossing and self-contact.
6. The broken line should have the minimal length.
You have to either find the length L of the constructed broken line, or determine that it is impossible to construct such a broken line.

Input

First line contains the number N (4 <= N <= 10000) - amount of points. Each of the following N lines contains coordinates of points separated by space xi and yi (1 <= i <= N). Points are given in random order.

Output

First line should contain the length of the broken line L or 0 if there is no solution.

Sample Input

Sample Output

40 00 33 33 0

Sample Output

12

Author: Alex Y. Suslov, Herman "Smash" NarkaytisResource: 5th Southern Subregional Contest. Saratov 2002Date: 2002-10-10

题解:

1.题目要求每条线段必须与x轴或y轴平行,所以每横行、竖行上必须有2的倍数个点

2.线段的构造是唯一的,画个图就知道了

3.可以先构造出图,再判断出线段是否相交

4.将与y轴平行的线段和与x轴平行的线段端点构造成线段树,从左到右依次扫描,遇到与x轴平行的线段的左端点,则插入它的横坐标,遇到右端点,则删除它的横坐标,遇到与y轴平行的线段,则判断在该线段范围(不算端点)内是否有点,如果有点,则相交,图形不合法

5.如遇到横坐标相同,则先处理与x轴平行的线段的右端点,再处理与y轴平行的线段,最后处理与x轴平行的线段的左端点


代码:

#include<stdio.h>#include<stdlib.h>#include<string.h>struct point{    int x, y, id;} p[10001];struct edge{    int x1, x2, y1, y2;} line[10001];struct event{    int id, x, type;} eve[30001];struct type_tree{    int a, b, t, l, r;} tree[100001];int n, num, connect[10001][2], ans, cnt, maxy = -1, miny = 99999, treenum;char vis[10001];void imp(){    printf("0\n");    exit(0);}void init(){    scanf("%d", &n);    for(int i = 1; i <= n; ++i)    {        scanf("%d%d", &p[i].x, &p[i].y);        p[i].id = i;        maxy = p[i].y > maxy ? p[i].y : maxy;        miny = p[i].y < miny ? p[i].y : miny;    }    if(n & 1) imp();}int cmp1(const void *a, const void *b){    struct point *c = (point *) a;    struct point *d = (point *) b;    if(c->y != d->y) return c->y - d->y;    return c->x - d->x;}int cmp2(const void *a, const void *b){    struct point *c = (point *) a;    struct point *d = (point *) b;    if(c->x != d->x) return c->x - d->x;    return c->y - d->y;}int cmp3(const void *c, const void *d){    struct event *a = (event*) c;    struct event *b = (event*) d;    if(a->x != b->x) return a->x - b->x;    return a->type - b->type;}void createpic(){    qsort(p + 1, n, sizeof(point), cmp1);    for(int i = 1; i <= n; i += 2)    {        if(p[i].y != p[i + 1].y) imp();        line[++num].x1 = p[i].x;        line[num].x2 = p[i + 1].x;        line[num].y1 = line[num].y2 = p[i].y;        connect[p[i].id][0] = p[i + 1].id;        connect[p[i + 1].id][0] = p[i].id;        ans += p[i + 1].x - p[i].x;        eve[++cnt].type = 0;        eve[cnt].x = p[i + 1].x;        eve[cnt].id = num;        eve[++cnt].type = 2;        eve[cnt].x = p[i].x;        eve[cnt].id = num;    }    qsort(p + 1, n, sizeof(point), cmp2);    for(int i = 1; i <= n; i += 2)    {        if(p[i].x != p[i + 1].x) imp();        line[++num].y1 = p[i].y;        line[num].y2 = p[i + 1].y;        line[num].x1 = line[num].x2 = p[i].x;        connect[p[i].id][1] = p[i + 1].id;        connect[p[i + 1].id][1] = p[i].id;        ans += p[i + 1].y - p[i].y;        eve[++cnt].type = 1;        eve[cnt].x = p[i].x;        eve[cnt].id = num;    }}void dfs(int now){    vis[now] = true;    if(!vis[connect[now][0]]) dfs(connect[now][0]);    if(!vis[connect[now][1]]) dfs(connect[now][1]);}void check_link(){    dfs(1);    for(int i = 1; i <= n; ++i)        if(!vis[i])            imp();}int settree(int a, int b){    int now = ++treenum;    tree[now].a = a;    tree[now].b = b;    if((a + b >> 1) > a)    {        tree[now].l = settree(a, a + b >> 1);        tree[now].r = settree(a + b >> 1, b);    }    return now;}void ins(int y, int id){    int a = tree[id].a, b = tree[id].b;    if(b - a <= 1) ++tree[id].t;    else    {        if(y <= a + b >> 1)  ins(y, tree[id].l);        else ins(y, tree[id].r);        tree[id].t = tree[tree[id].l].t + tree[tree[id].r].t;    }}void del(int y, int id){    int a = tree[id].a, b = tree[id].b;    if(b - a <= 1) --tree[id].t;    else    {        if(y <= a + b >> 1) del(y, tree[id].l);        else del(y, tree[id].r);        tree[id].t = tree[tree[id].l].t + tree[tree[id].r].t;    }}int find(int y1, int y2, int id){    int a = tree[id].a, b = tree[id].b;    if(y1 <= a && b <= y2) return tree[id].t;    if(b - a <= 1) return 0;    int ans = 0;    if(y1 <= (a + b >> 1)) ans |= find(y1, y2, tree[id].l);    if(y2 > (a + b >> 1)) ans |= find(y1, y2, tree[id].r);    return ans;}void check_cross(){    qsort(eve + 1, cnt, sizeof(event), cmp3);    settree(miny, maxy);    for(int i = 1; i <= cnt; ++i)    {        int id = eve[i].id;        if(!eve[i].type) del(line[id].y1, 1);        else if(eve[i].type == 2) ins(line[id].y1, 1);        else if(find(line[id].y1, line[id].y2, 1)) imp();    }}int main(){    init();    createpic();    check_link();    check_cross();    printf("%d\n", ans);    return 0;}
//ps:很奇怪,把 /2 改成 >> 1就过了。。。
//代码借鉴了网上大爷的。。。

0 0