UVa 11008 - Antimatter Ray Clearcutting

传送门

UVa 11008 - Antimatter Ray Clearcutting

题意

用一把激光枪,一枪可以打死同一直线上的树,求最少几枪可以干掉n - m颗树。

思路

状态压缩DP,但是不会做。
参考了Titanium的解题报告

用$dp[i]$表示在i这个状态的时候还要几枪才能达到目的,然后记忆化搜索。
还要好好体会。。。

代码

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int MAXN = 16 + 1;
const int INF = 0x3f3f3f3f;
 
struct TREE
{
    int x, y;
}tree[MAXN];
 
int slope[MAXN][MAXN], dp[(1 << 18)], n, m, remain;
 
int DFS(int sta)
{
    int i, sum = 0, j;
    int &cur = dp[sta];
    if (cur != -1)
        return cur;
    for (i = 0; i < n; i++)
        if ((1 << i) & sta)
            sum++;
    if (sum <= remain)
        return cur = 0;
    if (sum == 1)
        return cur = 1;
    cur = INF;
    for (i = 0; i < n; i++)
        if ((1 << i) & sta)
            for (j = i + 1; j < n; j++)
                if ((1 << j) & sta)
                    cur = min(cur, DFS(sta & (~slope[i][j])) + 1);
    return cur;
}
 
int main()
{
    //freopen("input.txt", "r", stdin);
    int T, i, j, cases = 0;
    scanf("%d", &T);
    while (T--)
    {
        memset(dp, -1, sizeof dp);
        scanf("%d%d", &n, &m);
        remain = n - m;
        for (i = 0; i < n; i++)
            scanf("%d%d", &tree[i].x, &tree[i].y);
        for (i = 0; i < n; i++)
            for (j = 0; j < n; j++)
            {
                if (i == j)
                    continue;
                for (int k = n - 1; k >= 0; k--)
                {
                    slope[i][j] <<= 1;
                    if ((tree[k].y - tree[i].y) * (tree[j].x - tree[i].x) == (tree[j].y - tree[i].y) * (tree[k].x - tree[i].x))
                        slope[i][j]++;
                }
            }
        int ans = DFS((1 << n) - 1);
        printf("Case #%d:\n%d\n", ++cases, ans);
        if (T)
            printf("\n");
    }
    return 0;
}

Powered by Jekyll and Theme by solid