[LightOJ 1018]Brush (IV)[状压DP]

题目链接:http://lightoj.com/volume_showproblem.php?problem=1018

题意分析:平面上有不超过N个点,现在可以任意方向划直线将它们划去,问:最少要划几次可以把所有的点划去?

解题思路:我们可以使用集合S表示:有哪些点还没有被划掉,然后转移 dp[s] = min(dp[s &(~line[i][j])]) + 1;这里涉及到line[i][j]的处理,它代表的是在i点和j点构成的直线上一共有几个点,需要预先处理。边界条件就是S中集合元素 >0 && <= 2时,肯定是1。元素空时就是0了。

个人感受:一开始想到的是用s代表当前点没被划过的集合,然后卡在了怎么转移上,想着选两个点遍历着判断这两个点所在直线有几个点,感觉炒鸡麻烦。然后就是翻了别人的题解,看到了预处理这字样,豁然开朗啊~

具体代码如下:

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 20;
int x[MAXN], y[MAXN], line[MAXN][MAXN], n, dp[1 << 16];

void init()
{
    memset(line, 0, sizeof line);
    memset(dp, 0x3f, sizeof dp);
    dp[0] = 0;
    for (int i = 0; i < n; ++i)
        for (int j = i + 1; j < n; ++j)
        {
            line[i][j] = (1 << i) | (1 << j);
            int dx = x[j] - x[i], dy = y[j] - y[i];
            for (int k = j + 1; k < n; ++k)
            {
                int dx2 = x[k] - x[i], dy2 = y[k] - y[i]; //这里我用了向量平行的条件
                if (dx2 * dy == dy2 * dx)
                    line[i][j] |= (1 << k);
            }
            line[j][i] = line[i][j];
        }
}

int dfs(int s)
{
    int& ret = dp[s];
    if (dp[s] < INF) return ret;
    int num = __builtin_popcount(s); //计算s中有几个1.很好用的函数
    if (num <= 2) return ret = 1;
    int i = 0;
    while (!(s & (1 << i))) ++i; //找出第一个没被删除的点
    for (int j = i + 1; j < n; ++j) //和其它点进行匹配。这里匹配次序是不会影响最终结果的
    {
        if (s & (1 << j))
        {
            ret = min(ret, dfs(s&(~line[i][j])) + 1);
        }
    }
    return ret;
}

int main()
{
	int t;
    for (int kase = scanf("%d", &t); kase <= t; ++kase)
    {
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
            scanf("%d%d", x+i, y+i);
        init();
        printf("Case %d: %d\n", kase, dfs((1 << n) - 1));
    }
	return 0;
}

版权声明:欢迎转载(^ω^)~不过转载请注明原文出处:http://blog.csdn.net/catglory ?(????)

时间: 2024-10-26 02:31:13

[LightOJ 1018]Brush (IV)[状压DP]的相关文章

LightOJ1018 Brush (IV)(状压DP)

题目大概说一个平面有n个灰尘,可以用一把刷子直直刷过去清理直线上的所有灰尘,问最少要刷几下才能清理完所有灰尘. 首先怎么刷其实是可以确定的,或者说直线有哪些是可以确定的,而最多就有C(n,2)条不一样的直线,即16*15/2=120: 然后容易想到用状压DP求解,d[S]表示已经清理的灰尘的状态是S最少刷的次数: 而转移就是通过枚举接下来使用那条直线,用我为人人的方式转移, 另外直线包含的灰尘集合状态一开始就可以预处理出来,这样时间复杂度O(2n*n2). 不过超时,超了800多ms.实在想不出

lightoj 1119 - Pimp My Ride(状压dp)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1119 题解:状压dp存一下车有没有被搞过的状态就行. #include <iostream> #include <cstring> #include <cstdio> using namespace std; typedef long long ll; ll dp[1 << 15] , val[15][15]; int main() {

[NOIP2016]愤怒的小鸟 D2 T3 状压DP

[NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可以用它向第一象限发射一只红色的小鸟,小鸟们的飞行轨迹均为形如y=ax2+bx的曲线,其中a,b是Kiana指定的参数,且必须满足a<0. 当小鸟落回地面(即x轴)时,它就会瞬间消失. 在游戏的某个关卡里,平面的第一象限中有n只绿色的小猪,其中第i只小猪所在的坐标为(xi,yi). 如果某只小鸟的飞行

ZOJ3305Get Sauce 状压DP,

状压DP的题目留个纪念,首先题意一开始读错了,搞了好久,然后弄好了,觉得DFS可以,最后超时,修改了很久还是超时,没办法看了一下n的范围,然后觉得状压可以,但是没有直接推出来,就记忆化搜索了一下,可是一直错,莫名奇妙,然后没办法看了一下题解,发现了下面这个比较好的方法,然后按照这个方程去推,然后敲,也是WA了好多把,写的太搓了,没人家的清楚明了,唉~也算是给自己留个纪念,状压一直做的都不太好~唉~还好理解了, 参考了  http://blog.csdn.net/nash142857/articl

poj 2411 Mondriaan&#39;s Dream(状压DP)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12232   Accepted: 7142 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in

HDU5816 Hearthstone(状压DP)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5816 Description Hearthstone is an online collectible card game from Blizzard Entertainment. Strategies and luck are the most important factors in this game. When you suffer a desperate situation an

HDU 4336 容斥原理 || 状压DP

状压DP :F(S)=Sum*F(S)+p(x1)*F(S^(1<<x1))+p(x2)*F(S^(1<<x2))...+1; F(S)表示取状态为S的牌的期望次数,Sum表示什么都不取得概率,p(x1)表示的是取x1的概率,最后要加一因为有又多拿了一次.整理一下就可以了. 1 #include <cstdio> 2 const int Maxn=23; 3 double F[1<<Maxn],p[Maxn]; 4 int n; 5 int main() 6

Travel(HDU 4284状压dp)

题意:给n个城市m条路的网图,pp在城市1有一定的钱,想游览这n个城市(包括1),到达一个城市要一定的花费,可以在城市工作赚钱,但前提有工作证(得到有一定的花费),没工作证不能在该城市工作,但可以走,一个城市只能工作一次,问pp是否能游览n个城市回到城市1. 分析:这个题想到杀怪(Survival(ZOJ 2297状压dp) 那个题,也是钱如果小于0就挂了,最后求剩余的最大钱数,先求出最短路和 Hie with the Pie(POJ 3311状压dp) 送披萨那个题相似. #include <