bzoj1027: [JSOI2007]合金

凸包,floyd求最小环。

首先第三个变量是可以由变量1,2得到的,所以可以省去。

然后如果产品在由原材料构成的凸包里,它就是可以被合成的。

所以问题就是要求包含所有产品的最小的凸包。

所以所有取到的边都在确定的一侧,所以先判断出哪些边可以取,跑floyd最小环就可以了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define eps 1e-10
using namespace std;
const int maxn = 500+10;
const int inf = 0x3f3f3f3f;

struct Point {
    double x,y;
    Point(double _x=0,double _y=0):x(_x),y(_y) {}
}mat[maxn],req[maxn];

struct Vector {
    double x,y;
    double operator* (Vector b) {return x*b.y-y*b.x;}    
    Vector(double _x=0,double _y=0):x(_x),y(_y) {}
    Vector(Point a,Point b):x(b.x-a.x),y(b.y-a.y) {}
};

double t;

int sgn(double x) {
    if(abs(x) < eps) return 0;
    else if(x>0) return 1;
    else return -1;    
}

bool check_line(Point ls,Point le,Point p) {
    return (ls.x>p.x && le.x>p.x) ||
           (ls.x<p.x && le.x<p.x) ||
           (ls.y>p.y && le.y>p.y) ||
           (ls.y<p.y && le.y<p.y) ;
}    

int g[maxn][maxn];
int n,m;

int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&mat[i].x,&mat[i].y,&t);
    for(int i=1;i<=m;i++) scanf("%lf%lf%lf",&req[i].x,&req[i].y,&t);
    for(int i=1;i<=n;i++) {
        bool flag=true;
        for(int j=1;j<=m;j++) 
            if(sgn(mat[i].x-req[j].x)||sgn(mat[i].y-req[j].y)) {flag=false; break;}
        if(flag) {printf("1\n",i); return 0;}
    }
    
    memset(g,0x3f,sizeof(g));
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++) if(i!=j){
        if(!sgn(mat[i].x-mat[j].x) && !sgn(mat[i].y-mat[i].y)) continue;
        
        bool able=true;
        for(int k=1;k<=m;k++) if(sgn(Vector(mat[i],mat[j])*Vector(mat[i],req[k]))==-1) {
            able=false;
            break;
        }
        if(able) {
            for(int k=1;k<=m;k++) 
                if(sgn(Vector(mat[i],mat[j])*Vector(mat[i],req[k]))==0&&check_line(mat[i],mat[j],req[k])) {
                    able=false;
                    break;
                }
        }
        if(able) g[i][j]=1;
    }
    
    int res=inf;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    for(int k=1;k<=n;k++)
        g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
    
    for(int i=1;i<=n;i++) 
    for(int j=1;j<=n;j++) {
        if(i!=j) res=min(res,g[i][j]+g[j][i]);
        else res=min(res,g[i][i]);
    }
    printf("%d\n",res>n?-1:res); 
    return 0;
}
posted @ 2016-06-14 18:07  invoid  阅读(148)  评论(0编辑  收藏  举报