LightOJ1018状压dp

/*****************************************
Author      :Crazy_AC(JamesQi)
Time        :2015
File Name   :
思路:题目的意思是,一个二维平面上面有不超过20个点,问最少用几条直线可以把点连完;
状压dp,line[i][j]的二进制中1的个数表示i与j之间有几个点,最后的转移方程是ret = min(ret,dfs(s & (1 << j)) + 1);
边界条件就是s中1的个数 <= 2,此时返回ret = 1;
详细代码见下文;
*****************************************/
// #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 <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <limits.h>
using namespace std;
#define MEM(a,b) memset(a,b,sizeof a)
#define pk push_back
template<class T> inline T Get_Max(const T&a,const T&b){return a < b?b:a;}
template<class T> inline T Get_Min(const T&a,const T&b){return a < b?a:b;}
typedef long long ll;
typedef pair<int,int> ii;
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 20;
int x[maxn],y[maxn],line[maxn][maxn],n,dp[1 << 16];
void init(){
	MEM(line,0);
	MEM(dp,0x3f);
	dp[0] = 0;
	for (int i = 0;i < n;++i){
		for (int j = i + 1;j < n;++j){
			line[i][j] = (1 << i) | (1 << j);
			// cout << line[i][j] << endl << endl;
			int dx = x[j] - x[i];
			int dy = y[j] - y[i];
			for (int k = j + 1;k < n;++k){
				int dx2 = x[k] - x[i];
				int dy2 = y[k] - y[i];
				if (dx2 * dy == dy2 * dx)
					line[i][j] |= (1 << k);
			}
			line[j][i] = line[i][j];
			// cout << line[i][j] << endl;
		}
	}
}


int dfs(int s){
	int& ret = dp[s];
	if (dp[s] < INF) return ret;
	int num = __builtin_popcount(s);
	if (num <= 2) return ret = 1;
	int i = 0;
	// cout << "s = " << s << endl;
	while(!(s & (1 << i))) {
		// cout << "i = " << i << endl;
		++i;
	}//找到没有删除的点
	for (int j = i + 1;j < n;++j){
		if (s & (1 << j)){
			ret = Get_Min(ret,dfs(s & (~line[i][j])) + 1);
		}
	}
	return ret;
}



int main()
{	
	// ios::sync_with_stdio(false);
	// freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);
	int t;
	for (int kase = scanf("%d",&t);kase <= t;++kase){
		scanf("%d",&n);
		for (int i = 0;i < n;++i)
			scanf("%d%d",x + i,y + i);
		init();
		printf("Case %d: %d\n",kase,dfs((1 << n) - 1));
	}
	return 0;
}


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