HDU 4380 Farmer Greedy 极角排序 DP

题意:有两种点,分别代表房子和金矿。我们要从代表房子中的点中取出三个点,这样会形成围成一个三角形,包围了若干个金矿。问有几种选取房子的方法,使三角形内的金矿的个数为奇数个。

思路:简单的暴力枚举。

           首先我们可以对房子的坐标排出极角序,作为计算方案的根据。

           然后我们固定一个点为最左最下的房子,然后枚举其他的两个房子,暴力求出围出的三角形中有多少个金矿。

          对于其他的三角形可能存在的情况,其实就是在上面的三角形上加加减减,得到有多少个金矿。

          最后统计答案即可。

代码如下:

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;

typedef long long LL;

const int N=105;
const int M=1005;
struct Point
{
    LL x,y;
}P1[N],P2[M];

int f[N][N][N];
int n,m;

LL cross(Point a,Point b,Point s)
{
    LL x1=a.x-s.x,y1=a.y-s.y;
    LL x2=b.x-s.x,y2=b.y-s.y;
    return x1*y2-x2*y1;
}
int dis2(Point a,Point b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*((a.y-b.y));
}

int cmp(Point a,Point b)
{
    if(cross(a,b,P1[0])>0)
        return 1;
    else return 0;
}

void init()
{
    int i,t;
    for(t=0,i=0;i<n;i++){
        if((P1[i].y-P1[t].y)<0 || (P1[i].y-P1[t].y==0 && P1[i].x-P1[t].x<0))
        t=i;
    }
    swap(P1[0],P1[t]);
    sort(P1+1,P1+n,cmp);
}

int cal(int x,int y,int z)
{
    int i;
    int sum=0;
    LL a,b,c;
    for (i=0;i<m;i++)
    {
        a=cross(P1[y],P2[i],P1[x]);
        b=cross(P1[z],P2[i],P1[y]);
        c=cross(P1[x],P2[i],P1[z]);
        if ((a>=0 && b>=0 && c>=0) || (a<=0 && b<=0 && c<=0))
        {
            sum++;
        }
    }
    return sum;
}

int main()
{
    //freopen("input.txt","r",stdin);
    int i,j,k;
    int CA=0;
    int ans=0;
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        ans=0;
        memset(P1,0,sizeof(P1));
        memset(P2,0,sizeof(P2));
        memset(f,0,sizeof(f));
        for (i=0;i<n;i++)
            scanf("%I64d%I64d",&P1[i].x,&P1[i].y);
        for (i=0;i<m;i++)
            scanf("%I64d%I64d",&P2[i].x,&P2[i].y);
        init();
        for (i=2;i<n;i++){
            for (j=1;j<i;j++){
                f[0][j][i]=cal(0,j,i);
                if (f[0][j][i]%2!=0) ans++;
            }
        }
        for (i=2;i<n;i++)
            for (j=1;j<i;j++)
                for (k=j+1;k<i;k++){
                    if (cross(P1[k],P1[i],P1[j])>0)
                        f[j][k][i]=f[0][j][k]+f[0][k][i]-f[0][j][i];
                    else
                        f[j][k][i]=f[0][j][i]-(f[0][j][k]+f[0][k][j]);
    
                    if (f[j][k][i]%2!=0) ans++;
                }
        printf("Case %d: ",++CA);
        printf("%d\n",ans);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值