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开始算一样….
可以省时间~
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; }
相关文章推荐
- 英语学习的一个本人认为最重要的技巧
- 一个比较完美的spacerdiv技巧
- Qt技巧:Win7下打包发布Qt程序(解释的比较清楚,把exe和dll伪装合并成一个文件)
- 一个对我比较重要的字符串类使用错误
- lightoj 1021 从当前转移到其他状态的状压dp
- 一个比较完美的spacer div技巧
- 一个有意思的C++泛型比较技巧文章
- 动态规划中转移方程的一个技巧
- 记录一个Word操作技巧,很偏门的,鉴于Google很不方便用了,百度起来比较费劲所以记录一下
- lightoj1018(状态压缩dp)
- 当web应用中面临大数据量同时并发量比较大的情况下性能是一个尤为重要的问题,面对性能优化我们应从何做起,在哪些方面做优化呢?
- 练习1-24: 编写一个程序,查找C语言程序中的基本语法错误,如圆括号,方括号以及花括号不配对等。要正确的处理引号(包括单引号,双引号)~转移字符序列与注释(如果读者想把该程序编写成完全通用的程序,难度会比较大。)
- 设计技巧26:状态模式 State 用类来表示一个状态
- LightOJ - 1018 Brush (IV)(状态压缩DP)
- lightoj 1018 (状态压缩DP)
- 一个比较完美的spacer div技巧
- 设计技巧6:单一的状态 MonoState (Mono 单一的) 多个实例共享同一个状态
- 【重要】攻击动作时间段判断~使用动画time比较动画length和使用一个变量数组做延迟
- 每次推荐一个----Android Studio中的几个比较重要的快捷键ctrl+shift+i
- LightOJ 1018 Brush (IV)(状态压缩DP)