题意:一个网格内(5*5)有n个点,问最少多少条线可以把这些点划掉。
题解:以前做过这种类型的题,先把共线点用二进制数表示出来,然后dp的时候传入全1的状态,dp函数内枚举两点消除其他共线点,最后得到最小值,但这道题用这种方法会超时。。。所以要有新的解法,根据题解。。。。。需要添加两个数组nbits[1 << 20]和first[1 << 20],分别表示存储当前状态有几个1和然后当前状态的第一个0位的位置,dp时有两个参数s和cnt,初始都是0,表示刚开始点都没有被划掉,且线的数量为0,然后用f[1 << 20]和g[1
<< 20]分别表示当前状态是否被扫描过和当前状态最优的划线值,dp主要思想是从当前状态第一个0位开始(第一个未被划掉的点),枚举后面的每一个点(位是1也有可能,已经划掉也不一定是最优),划掉共线点找到最优解,一堆剪枝,(1)如果当前划线数量cnt超过g[s],(2)或者cnt > res,都可以return,(3)然后如果剩余1位数量<=2,直接res = cnt + 1。最后注意的是输入点可能会重复,需要去重点。
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int N = 21; struct P { int x, y; }p[N]; int f[1 << 20];//判断当前状态是否扫描过 int line[N][N];//判断和i、j共线的点 int flag[6][6];//判断点(x, y)是否出现过 int g[1 << 20];//判断当前状态有多少条线划过(最优) int first[1 << 20];//判断当前状态第一个0的位置 int nbits[1 << 20];//计算当前状态有多少个1 int n, res, test; bool judge(int i, int j, int k) { return (p[j].y - p[i].y) * (p[k].x - p[i].x) == (p[k].y - p[i].y) * (p[j].x - p[i].x) ? 1 : 0; } void dp(int s, int cnt) { if (f[s] == test && g[s] <= cnt) return; f[s] = test; g[s] = cnt; if (cnt >= res) return; if (nbits[s] == n) { res = cnt; return; } if (n - nbits[s] <= 2) { res = cnt + 1; return; } for (int i = first[s] + 1; i < n; i++) dp(s | line[first[s]][i], cnt + 1); } int main() { for (int i = 0; i < (1 << 20); i++) { nbits[i] = 0; first[i] = -1; for (int j = 0; j < 20; j++) { if (1 & (i >> j)) nbits[i]++; else if (first[i] == -1) first[i] = j; } } memset(f, 0, sizeof(f)); int t, cas = 1; scanf("%d", &t); for (int ii = 1; ii <= t; ii++) { memset(flag, 0, sizeof(flag)); res = 6; test = ii; scanf("%d", &n); int a, b; for (int i = 0; i < n; i++) { scanf("%d%d", &a, &b); flag[a][b] = 1; } n = 0; for (int i = 0; i < 6; i++) for (int j = 0; j < 6; j++) if (flag[i][j]) { p[n].x = i; p[n++].y = j; } for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++) { int s = (1 << i) | (1 << j); for (int k = 0; k < n; k++) { if (k == i || k == j) continue; if (judge(i, j, k)) s |= (1 << k); } line[i][j] = s; } dp(0, 0); printf("Case %d: %d\n", cas++, res); } return 0; }
时间: 2024-10-11 11:39:14