lightoj1018_状压dp

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

题目描述:

  有n个点,问最少用几条无线长的线段把这n个点全部覆盖起来?
解题思路:
  其实应该换一种枚举方式,先预处理出来每条线段,对每一个状态选择两个不在状态的点,然后画以两个点为端点的线,来进行状态转移。这个题目最重要的优化在于如何挑选不在状态的两个点,测试实力比较多,我们可以预处理出来每个状态未覆盖的点。

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <vector>
 7 #include <ctime>
 8 #include <queue>
 9 #include <list>
10 #include <set>
11 #include <map>
12 using namespace std;
13 #define INF 0x3f3f3f3f
14 typedef long long LL;
15 
16 int x[20], y[20], dp[1<<16], line[20][20];
17 vector <int> p[1<<16];
18 void init()
19 {
20     for(int i = 0; i < (1<<16); i++)
21     {
22         for(int j = 0; j < 16; j++)
23         {
24             if((i & (1<<j)))
25                 continue;
26             p[i].push_back(j);
27         }
28     }
29 }
30 int check(int i, int j, int k)
31 {
32     int y2 = y[j], y1 = y[i], y3 = y[k];
33     int x2 = x[j], x1 = x[i], x3 = x[k];
34     if(y3*(x2-x1)==(y2-y1)*x3+x2*y1-x1*y2)
35         return 1;
36     else
37         return 0;
38     //return (y2-y1)*(x3-x2) == (y3-y2)*(x2-x1);
39 }
40 int main()
41 {
42     int t, n;
43     scanf("%d", &t);
44     init();
45     for(int ca = 1; ca <= t; ca++)
46     {
47         scanf("%d", &n);
48         for(int i = 0; i < n; i++)
49             scanf("%d %d", &x[i], &y[i]);
50         memset(line, 0, sizeof(line));
51         for(int i = 0; i < n; i++)
52         {
53             line[i][i] = (1<<i);
54             for(int j = i+1; j < n; j++)
55             {
56                 for(int k = 0; k < n; k++)
57                 {
58                     if(check(i, j, k))
59                         line[i][j] |= (1<<k);
60                 }
61             }
62         }
63         memset(dp, INF, sizeof(dp));
64         dp[0] = 0;
65         for(int i = 0; i < (1<<n) -1; i++)//这里一定要减1,不然会re,我re了n发 = =
66         {
67             int x = p[i][0];
68             for(int j = 0; j < p[i].size(); j++)
69             {
70                 int y = p[i][j];
71                 dp[i|line[x][y]] = min(dp[i|line[x][y]], dp[i]+1);
72             }
73         }
74         printf("Case %d: %d
", ca, dp[(1<<n)-1]);
75     }
76     return 0;
77 }
View Code
原文地址:https://www.cnblogs.com/luomi/p/5950721.html