一看题目就知道是状态压缩 DP
然后n棵树至少要砍掉m棵
每次可以去掉一整行的树 斜着也可以 求最少的次数
开始不知道怎么存一整行 百度了 然后是用一个二维数组a[i][j] 里面一个二进制 表示可以朝i j这个发现去掉的树
然后i == j的时候我是 a[i][j] = 1<i 表示一棵树的情况 因为不知道方向
网上大多数是记忆化搜索 递推也行
还需好好消化
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 18;
int a[maxn][maxn];
int dp[1<<maxn];
int x[maxn];
int y[maxn];
int bitcount(int x)
{
int ret = 0;
while(x)
{
if(x&1)
ret++;
x >>= 1;
}
return ret;
}
int main()
{
int cas = 1;
int T;
scanf("%d", &T);
while(T--)
{
int n, m;
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i++)
scanf("%d %d", &x[i], &y[i]);
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{
a[i][j] = 0;
if(i == j)
{
a[i][j] = 1<<i;
continue;
}
for(int k = 0; k < n; k++)
{
//(x[i]-x[k])/(y[i]-y[k]) == (x[j]-x[k])/(y[j]-y[k])
if((x[i]-x[k])*(y[j]-y[k]) == (x[j]-x[k])*(y[i]-y[k]))
a[i][j] |= (1<<k);
}
}
int ans = 999999999;
/*for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
printf("%d ", a[i][j]);
}
puts("");
}*/
dp[0] = 0;
for(int s = 1; s < (1<<n); s++)
{
int cnt = bitcount(s);
int i, j;
dp[s] = 999999999;
for(i = 0; i < n; i++)
if(s & (1<<i))
break;
for(j = i; j < n; j++)
{
if(s & (1<<j))
{
dp[s] = min(dp[s], dp[s&(~a[i][j])]+1);
if(cnt >= m)
ans = min(ans, dp[s]);
}
}
}
printf("Case #%d:\n", cas++);
printf("%d\n", ans);
if(T)
puts("");
}
return 0;
}
/*
2
4
4
0 0
0 1
1 0
1 1
9
7
0 0
1 1
0 2
2 0
2 2
3 0
3 1
3 2
3 4
*/