hdu 4739 Zhuge Liang's Mines(状压DP)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4739

题目大意:二维平面给你n个点,4个能组成一个正方形的点能一起消除,问你最多能消除几个?

思路:因为只有20个点,就状压一下,然后就是 d[ s|s1 ] |= d[ s1 ],这里s1是某4个能组成正方形的点且不包含在s里面,读入的时候处理一下s1就可以了。可以直接dfs过去,找到最长路径就好了。

自己做的时候,是枚举状态这样做的,先开始由于没有没有去处理s1,而是枚举所有四个点的状态,然后再去判断,一直TLE。。。然后优化优化,最后终于优化到了这一步。。挺简单的优化,为什么最先开始会没想到。。。 = =

代码如下:

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

const int MAXN = 22;

struct Point
{
    int x,y;
    bool operator < (const Point & tmp) const
    {
        if(x == tmp.x) return y < tmp.y;
        else return x < tmp.x;
    }
} p[MAXN];

int is_sq(int a,int b,int c,int d)
{
    if(p[a].x== p[b].x)
    {
        int l1 = p[b].y - p[a].y;
        if(p[b].y == p[d].y)
        {
            int l2 = p[d].x - p[b].x;
            if(l1 == l2 && p[a].y == p[c].y)
            {
                int l3 = p[c].x- p[a].x;
                if(l2 == l3 && p[c].x == p[d].x)
                {
                    int l4 = p[d].y - p[c].y;
                    if(l3 == l4)
                        return 1;
                }
            }
        }
    }
    return 0;
}

int tot;
int sta[5555];
bool vis[1<<22];

int ans;

void dfs(int s,int cnt)
{
    //printf("s = %d,cnt = %d\n",s,cnt);
    ans = max(ans,cnt);
    vis[s] = 1;
    for(int i = 0;i < tot;i++)
    {
        if((sta[i]&s) == 0 && !vis[s|sta[i]])
        {
            dfs(s|sta[i],cnt + 4);
        }
    }
}

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        if(n == -1) break;
        for(int i = 0;i<n;i++)
            scanf("%d%d",&p[i].x,&p[i].y);
        sort(p,p+n);
        tot=0;
        for(int i = 0;i<n;i++)
            for(int j = i+1;j<n;j++)
                for(int k = j+1;k<n ;k++)
                    for(int l = k+1;l<n;l ++)
                    {
                        if(is_sq(i,j,k,l))
                        {
                            sta[tot++] = (1<<i) + (1<<j) + (1<<k) + (1<<l);
                        }
                    }
        ans = 0;
        //printf("tot = %d\n",tot);
        memset(vis,0,sizeof(vis));
        dfs(0,0);
        printf("%d\n",ans);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值