您的位置:首页 > 其它

lightoj 1018 一个比较重要的状态转移的剪枝技巧....DFS+状压dp

2016-09-21 16:28 387 查看
Mubashwir returned home from the contest and got angry after seeing his room dusty. Who likes to see a dusty room after a brain storming programming contest? After checking a bit he found an old toothbrush in his room. Since the dusts are scattered everywhere, he is a bit confused what to do. So, he called Shakib. Shkib said that, ‘Use the brush recursively and clean all the dust, I am cleaning my dust in this way!’

So, Mubashwir got a bit confused, because it’s just a tooth brush. So, he will move the brush in a straight line and remove all the dust. Assume that the tooth brush only removes the dusts which lie on the line. But since he has a tooth brush so, he can move the brush in any direction. So, he counts a move as driving the tooth brush in a straight line and removing the dusts in the line.

Now he wants to find the maximum number of moves to remove all dusts. You can assume that dusts are defined as 2D points, and if the brush touches a point, it’s cleaned. Since he already had a contest, his head is messy. That’s why he wants your help.

Input

Input starts with an integer T (≤ 1000), denoting the number of test cases.

Each case starts with a blank line. The next line contains three integers N (1 ≤ N ≤ 16). N means that there are N dust points. Each of the next N lines will contain two integers xi yi denoting the coordinate of a dust unit. You can assume that (-1000 ≤ xi, yi ≤ 1000) and all points are distinct.

Output

For each case print the case number and the minimum number of moves.

Sample Input

Output for Sample Input

2

3

0 0

1 1

2 2

3

0 0

1 1

2 3

Case 1: 1

Case 2: 2

这个题思路不难,一开始预处理任意两个点都会经过哪些点就行了,但是有一点小技巧的

因为是状压dp,所以想要找到前一个状态就要减掉当前两点及其经过的点

这个在记录的时候直接用1《i来加进去就可以

但是不能忘了把端点本身也加进去

再就是很关键的一点

剪枝

这个剪枝就剪在dfs的时候

比如111111111要从前一次的状态中搜索,那么他的第一个端点只要找一个就可以,前提是这个端点是没被删除的

这里需要做一些处理,标记好他

第二个端点要找a端点后面的就可以了

因为每次第一个端点都是第一个,这样后期搜索就不再需要最开始的端点

达到剪枝的目的…

感觉是卡常了,但是这个技巧还是要学会的

就好比冒泡排序的内层循环总是从外层+1开始算一样….

可以省时间~

#include<iostream>
#include<queue>
#include<stack>
#include<cstdio>
#include<memory.h>
#include<algorithm>
#include<vector>
using namespace std;
int n;
int inf=0x3f3f3f3f;
struct q
{
int x,y;
};
q dian[17];
bool sandiangongxian(q a,q b,q c)
{
if((a.x-b.x)*(b.y-c.y)==(a.y-b.y)*(b.x-c.x))return 1;
else return 0;
}
int dp[1<<17];
bool biaoji[1<<17];
int tu[18][18];
int titi[17]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536};
int dfs(int qingkuang)
{
if(qingkuang<=0)return dp[0]=0;
if(biaoji[qingkuang])return dp[qingkuang];
for(int a=0;a<=n;a++)
{
if(qingkuang==titi[a])return dp[qingkuang]=1;
}
int sum=inf;
int qi[17];
int u=qingkuang;
for(int q=1;u>0;q++,u>>=1)qi[q]=u&1;
for(int a=1;a<=n;a++)
{
if(!qi[a])continue;
for(int b=a+1;b<=n;b++)
{
if(!qi[b])continue;
int qian=qingkuang&(~tu[a][b]);
int we=dfs(qian);
sum=min(sum,we);
}
break;
}
biaoji[qingkuang]=1;
return dp[qingkuang]=min(dp[qingkuang],sum+1);
}
int main()
{
int T;
cin>>T;
int u=0;
while(T--)
{
memset(dp,0x3f,sizeof(dp));
memset(dian,0,sizeof(dian));
memset(tu,0,sizeof(tu));
memset(biaoji,0,sizeof(biaoji));
cin>>n;
for(int a=1;a<=n;a++)cin>>dian[a].x>>dian[a].y;
for(int a=1;a<=n;a++)
{
for(int b=1;b<=n;b++)
{
if(a==b)continue;
tu[a][b]+=1<<(a-1);
tu[a][b]+=1<<(b-1);
for(int c=1;c<=n;c++)
{
if(c==a||c==b)continue;
if(sandiangongxian(dian[a],dian[b],dian[c]))
{
tu[a][b]+=1<<(c-1);
}
}
}
}
int qiu=dfs((1<<n)-1);
printf("Case %d: %d\n",++u,qiu);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐