HDU 4739 Zhuge Liang's Mines(DP)

该题一开始没想出怎么暴力, 其实我们可以先预处理出来所有的可能正方形,存到一个vector里,然后用dp的思想就行了。

因为最多只有20个点,所以我们可以状态压缩一下,然后状态转移就是d[S] = max(ans,dp(ss)+4);   如果当前这个正方形所组成的点完全在S中,那么ss就是S去掉这四个点后的状态,如此转移就可以了。

细节参见代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
using namespace std;
typedef long long ll;
const int INF = 1000000000;
const int maxn = 23;
int T,n,kase=0,len,m,d[1<<maxn], vis[1<<maxn];
struct node {
    int x, y;
    node(int xx=0, int yy=0):x(xx), y(yy) {}
    bool operator < (const node& rhs) const {
        return x < rhs.x || (x == rhs.x && y < rhs.y);
    }
}a[maxn];
vector<int> g;
int dp(int S) {
    if(vis[S] == kase) return d[S];
    vis[S] = kase;
    int& ans = d[S];
    ans = 0;
    for(int i=0;i<len;i++) {
        int v = g[i];
        if((S|v) == S) {
            int ss = S ^ v;
            ans = max(ans,dp(ss)+4);
        }
    }
    return ans;
}
int main() {
    while(~scanf("%d",&n)) {
        if(n < 0) return 0;
        g.clear();
        for(int i=0;i<n;i++) scanf("%d%d",&a[i].x,&a[i].y);
        sort(a,a+n);
        for(int i=0;i<n;i++) {
            for(int j=i+1;j<n;j++) {
                if(a[i].x != a[j].x) break;
                for(int ii=j+1;ii<n;ii++) {
                    for(int jj=ii+1;jj<n;jj++) {
                        if(a[ii].x != a[jj].x) break;
                        if(a[i].y == a[ii].y && a[j].y == a[jj].y && a[j].y-a[i].y == a[ii].x-a[i].x) {
                            int v = 0;
                            v |= (1<<i); v |= (1<<j);
                            v |= (1<<ii); v |= (1<<jj);
                            g.push_back(v);
                        }
                    }
                }
            }
        }
        len = g.size();
        ++kase;
        printf("%d\n",dp((1<<n)-1));
    }
    return 0;
}


你可能感兴趣的:(dp,HDU,状态压缩,ACM-ICPC)