LightOJ 1018 Brush (IV)

题意:给n个点,问最少需要几条直线覆盖所有点

这是一道状压dp,还要记忆化搜索,复杂度并不清楚,以后再解决

dp[s]:最少需要几条直线覆盖s中的点

转移时点数小于等于2时容易解决

如果点数大于2,先选定一点,再枚举另一个点

若选定点i,j,令ns为添加直线pi-pj后剩下的点

则还需要 dp[ns] 条直线来覆盖所有的点

预处理line[i][j]:直线pi-pj所能覆盖的点

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

struct P{int x, y;}p[18];
bool in_one_line(P a, P b, P c) {return (b.x - a.x) * (c.y - a.y) == (c.x - a.x) * (b.y - a.y);}

int n, dp[1 << 16];
int line[18][18];

int dfs(int s)
{
    if(dp[s] != 100) return dp[s];

    int cnt = 0;
    for(int i = 0; i < n; i++)
        if(s & (1 << i)) cnt++;
    if(cnt == 0) return dp[s] = 0;
    if(cnt <= 2) return dp[s] = 1;

    for(int i = 0; i < n; i++)
    {
        if(!(s & (1 << i))) continue;
        for(int j = i + 1; j < n; j++)
        {
            if(!(s & (1 << j))) continue;
            dp[s] = min(dp[s], dfs( s^(s&line[i][j]) ) + 1);
        }
        break;
    }
    return dp[s];
}

int main()
{
    int T;
    scanf("%d", &T);

    for(int ca = 1; ca <= T; ca++)
    {
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
            scanf("%d%d", &p[i].x, &p[i].y);

        for(int i = 0; i < n; i++)
            for(int j = i + 1; j < n; j++)
            {
                line[i][j] = (1 << i) + (1 << j);
                for(int k = 0; k < n; k++)
                    if(in_one_line(p[i], p[j], p[k]))
                        line[i][j] |= (1 << k);
            }

        for(int s = 0; s < (1 << n); s++)
            dp[s] = 100;

        printf("Case %d: %d\n", ca, dfs((1 << n) - 1));
    }

    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值