lightoj 1018 - Brush (IV) 【状压dp】

190 篇文章 2 订阅
84 篇文章 2 订阅

题面

题意

给一些点,问最少可以用几条直线将他们全部覆盖.

方法

因为n<=16,故方法为状压dp
首先预处理出任意两条直线所能覆盖的点,之后枚举来更新状态

枚举方法

首先枚举状态(基本规律,这样效率更高),然后添加直线的一个端点为该状态下第一个未覆盖的点,枚举另外一个,并用这两点组成的直线来更新状态,这样复杂度仅为 O ( n ∗ 2 n ) O(n*2^{n}) O(n2n)
若不先枚举状态,先枚举其中一个点,则无法利用状态来确定另外一个点,故不得不再枚举另外一个点,复杂度为 O ( n 2 ∗ 2 n ) O(n^{2}*2^{n}) O(n22n).

代码

#include<bits/stdc++.h>
#define db double
#define N 70000
#define M 20
using namespace std;

int T,TT,n,dp[N],x[M],y[M],tmp,each[M][M],eve[M][M];

inline int read()
{
	char ch=getchar();
	int an=0,f=1;
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while('0'<=ch&&ch<='9'){
		an=an*10+ch-'0';
		ch=getchar();
	}
	return an*f;
}

inline bool pd(int u1,int v1,int u2,int v2,int u3,int v3)
{
	if((v3-v1)*(u2-u1)==(v2-v1)*(u3-u1)) return 1;
	return 0;
}


int main()
{
	int i,j,k,l;
	scanf("%d",&T);
	TT=T;
	each[1][1]=0;
	each[2][1]=2;
	each[2][2]=1;
	each[3][1]=6;
	each[3][2]=5;
	each[3][3]=3;
	each[4][1]=14;
	each[4][2]=13;
	each[4][3]=11;
	each[4][4]=7;
	each[5][1]=30;
	each[5][2]=29;
	each[5][3]=27;
	each[5][4]=23;
	each[5][5]=15;
	each[6][1]=62;
	each[6][2]=61;
	each[6][3]=59;
	each[6][4]=55;
	each[6][5]=47;
	each[6][6]=31;
	each[7][1]=126;
	each[7][2]=125;
	each[7][3]=123;
	each[7][4]=119;
	each[7][5]=111;
	each[7][6]=95;
	each[7][7]=63;
	each[8][1]=254;
	each[8][2]=253;
	each[8][3]=251;
	each[8][4]=247;
	each[8][5]=239;
	each[8][6]=223;
	each[8][7]=191;
	each[8][8]=127;
	each[9][1]=510;
	each[9][2]=509;
	each[9][3]=507;
	each[9][4]=503;
	each[9][5]=495;
	each[9][6]=479;
	each[9][7]=447;
	each[9][8]=383;
	each[9][9]=255;
	each[10][1]=1022;
	each[10][2]=1021;
	each[10][3]=1019;
	each[10][4]=1015;
	each[10][5]=1007;
	each[10][6]=991;
	each[10][7]=959;
	each[10][8]=895;
	each[10][9]=767;
	each[10][10]=511;
	each[11][1]=2046;
	each[11][2]=2045;
	each[11][3]=2043;
	each[11][4]=2039;
	each[11][5]=2031;
	each[11][6]=2015;
	each[11][7]=1983;
	each[11][8]=1919;
	each[11][9]=1791;
	each[11][10]=1535;
	each[11][11]=1023;
	each[12][1]=4094;
	each[12][2]=4093;
	each[12][3]=4091;
	each[12][4]=4087;
	each[12][5]=4079;
	each[12][6]=4063;
	each[12][7]=4031;
	each[12][8]=3967;
	each[12][9]=3839;
	each[12][10]=3583;
	each[12][11]=3071;
	each[12][12]=2047;
	each[13][1]=8190;
	each[13][2]=8189;
	each[13][3]=8187;
	each[13][4]=8183;
	each[13][5]=8175;
	each[13][6]=8159;
	each[13][7]=8127;
	each[13][8]=8063;
	each[13][9]=7935;
	each[13][10]=7679;
	each[13][11]=7167;
	each[13][12]=6143;
	each[13][13]=4095;
	each[14][1]=16382;
	each[14][2]=16381;
	each[14][3]=16379;
	each[14][4]=16375;
	each[14][5]=16367;
	each[14][6]=16351;
	each[14][7]=16319;
	each[14][8]=16255;
	each[14][9]=16127;
	each[14][10]=15871;
	each[14][11]=15359;
	each[14][12]=14335;
	each[14][13]=12287;
	each[14][14]=8191;
	each[15][1]=32766;
	each[15][2]=32765;
	each[15][3]=32763;
	each[15][4]=32759;
	each[15][5]=32751;
	each[15][6]=32735;
	each[15][7]=32703;
	each[15][8]=32639;
	each[15][9]=32511;
	each[15][10]=32255;
	each[15][11]=31743;
	each[15][12]=30719;
	each[15][13]=28671;
	each[15][14]=24575;
	each[15][15]=16383;
	each[16][1]=65534;
	each[16][2]=65533;
	each[16][3]=65531;
	each[16][4]=65527;
	each[16][5]=65519;
	each[16][6]=65503;
	each[16][7]=65471;
	each[16][8]=65407;
	each[16][9]=65279;
	each[16][10]=65023;
	each[16][11]=64511;
	each[16][12]=63487;
	each[16][13]=61439;
	each[16][14]=57343;
	each[16][15]=49151;
	each[16][16]=32767;
	
	while(T--)
	{
		n=read();
		for(i=1;i<=(1 << n)-1;i++) dp[i]=M;
		for(i=1;i<=n;i++)
		{
			scanf("%d",&x[i]);
			scanf("%d",&y[i]);
		}
		
		for(i=1;i<=n;i++)
		{
			for(k=i+1;k<=n;k++)
			{
				tmp=(1 << (i-1))|(1 << (k-1));
				for(l=i+1;l<=n;l++)
				{
					if(l==k) continue;
					if(pd(x[i],y[i],x[k],y[k],x[l],y[l]))
					{
						tmp|=(1 << (l-1));
					}
				}
				eve[i][k]=tmp;
			}
		}
		
		for(j=0;j<(1 << n)-1;j++)
		{
			if(dp[j]==M) continue;
			for(i=1;i<=n;i++)
			{
				if(!(j & (1 << (i-1)))) break;
			}
			for(k=i+1;k<=n;k++)
			{
				if((j&(1<<(k-1)))!=0) continue;
				tmp=eve[i][k];
				dp[j|tmp]=min(dp[j|tmp],dp[j]+1);
			}
		}
		
		for(i=1;i<=n;i++)
		{
			dp[(1 << n)-1]=min(dp[(1 << n)-1],dp[each[n][i]]+1);
		}
		
		printf("Case %d: %d\n",TT-T,dp[(1 << n)-1]);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值