lightoj 1018 - Brush (IV)

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

题意分析:二分平面上有N个点,现在有一把可沿着任何方向走的刷子可以刷去这些点,问最少需要刷出多少条直线可以把点刷完?

解题思路:这个是个比较典型的状压dp问题,首先N不大,可以用二进制表示每个点的状态,1表示还没有被刷掉,0表示被刷掉了。

那么状态from中有num个1,如果num<=2显然是为1的,0的话就是0。那么我们想法刷掉from中的点,这样就可以得到状态to,比如我们刷掉的是i,j两个点,显然,这两个点中间的点也会被刷掉,用line[i][j]表示这两点之间点的状态,然后对应着把from中对应line[i][j]的点变成0,这样就得到状态to了,dp[from]=min(dp[from],dp[from|line[i][j]]+1)。

当然也可以写成记忆画搜索的。。。

感悟:由于开始没有想到line这个东西,直接枚举三点一线的情况来进行状态转移,TLE到爆,本地跑随机的120组数据就要花10s以上的时间,更不要说题目给的3000这么大的数了。

/*****************************************
Author      :Crazy_AC(JamesQi)
Time        :2015
File Name   :
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
using namespace std;
#define MEM(x,y) memset(x, y,sizeof x)
#define pk push_back
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
const double eps = 1e-10;
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 17;
int line[maxn][maxn];
int dp[1<<maxn];
int t,icase=0;
int n;
int x[maxn],y[maxn];
bool check(int i,int j,int k){
    ii A(x[i]-x[j],y[i]-y[j]);
    ii B(x[i]-x[k],y[i]-y[k]);
    return A.first*B.second-A.second*B.first==0;
}
inline void Initation(){
    for (int i=0;i<n;++i){
        for(int j=i+1;j<n;++j){
            for (int k=0;k<n;++k){
                if (check(i,j,k))
                    line[i][j] |= 1<<k;
            }
            line[j][i]=line[i][j];
        }
    }
}
// int dfs(int cur){
//     if (dp[cur] < INF) return dp[cur];
//     int num = __builtin_popcount(cur);
//     if (num <= 2) return 1;
//     int i=0;
//     while(!(cur&(1<<i)))i++;
//     for(int j=i+1;j<n;++j){
//         if (cur&(1<<j)){
//             dp[cur]=min(dp[cur],dfs(cur &(~line[i][j]))+1);
//         }
//     }
//     return dp[cur];
// }
vector<int> G[1 << maxn];
int main()
{    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    for (int i=0;i<70000;++i){
        for(int j=0;j<maxn;++j){
            if ((i&(1<<j))==0)
                G[i].push_back(j);
        }
    }
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        memset(line, 0,sizeof line);
        memset(dp,INF,sizeof dp);
        dp[0]=0;
        for (int i=0;i<n;++i){
            scanf("%d%d",&x[i],&y[i]);
            line[i][i] = (1<<i);
        }
        Initation();
        cout << "Case " << ++icase << ": ";
        int up=1<<n;
        for (int i=0;i<up;++i){
            int xx=G[i][0];
            for (int j=0;j<G[i].size();++j){
                int yy=G[i][j];
                dp[i|line[xx][yy]]=min(dp[i|line[xx][yy]],dp[i]+1);
            }
        }
        cout << dp[up-1] <<endl;
        // cout << dfs((1<<n)-1) << endl;
    }
    return 0;
}


你可能感兴趣的:(dp,lightoj)