zoukankan      html  css  js  c++  java
  • 【洛谷P4460】解锁屏幕【状压dp】

    题目大意:

    题目链接:https://www.luogu.org/problemnew/show/P4460
    给出坐标系中nn个点的坐标,求有多少种连线方式使得没有连线经过在连这条线之前没有经过的点。


    思路:

    很容易发现,对于任意阶段,影响接下来连线的只有两个因素:已连线的点集和最后连到的点。
    由于n20nleq 20,所以可以状压。
    枚举点集、最后连到的点以及接下来要连的点。之后枚举所有没有选择的点,用叉积(或斜率)判断是否满足要求。这样我们就得到了一个暴力O(2n×n3)O(2^n imes n^3)的做法。
    考虑能否压掉枚举没选择的点那一维。可以预处理出line[i][j]line[i][j]表示线段ijij中经过的点集(不包括iijj)。那么只要判断没选择的点集(~ss)和line[i][j]line[i][j]是否有交集就可以了。
    时间复杂度O(2n×n2)O(2^n imes n^2)。跑得比较慢,但是stdstd的复杂度就是这样的了。


    代码:

    #pragma GCC optimize("Ofast")
    #pragma GCC optimize("inline")
    #include <cstdio>
    #include <iostream>
    #define rr register
    using namespace std;
    
    const int N=30,MAXN=(1<<20)+10,MOD=100000007;
    int n,ans,maxn,x[N],y[N],f[MAXN][N],line[N][N];
    
    bool in(int k,int q,int p)
    {
    	if (x[k]<min(x[q],x[p])) return 0;
    	if (x[k]>max(x[q],x[p])) return 0;
    	if (y[k]<min(y[q],y[p])) return 0;
    	if (y[k]>max(y[q],y[p])) return 0;
    	return 1;
    }
    
    bool check1(int s,int k)
    {
    	return s&(1<<k-1);
    }
    
    bool check2(int q,int p,int k)
    {
    	if (in(k,q,p)&&(x[k]-x[q])*(y[p]-y[k])==(x[p]-x[k])*(y[k]-y[q])) return 0;
    	return 1;
    }
    
    bool check3(int s)
    {
    	int cnt=0;
    	for (;s;s>>=1)
    		if (s&1) cnt++;
    	return cnt>3;
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d%d",&x[i],&y[i]);
    		f[1<<i-1][i]=1;
    	}
    	maxn=1<<n;
    	for (rr int i=1;i<=n;i++)
    		for (rr int j=1;j<=n;j++)
    			for (rr int k=1;k<=n;k++)
    				if (!check2(i,j,k)&&i!=j&&j!=k&&i!=k) line[i][j]|=(1<<k-1);
    	for (rr int s=0;s<maxn;s++)
    		for (rr int i=1;i<=n;i++)
    			if (check1(s,i))
    				for (rr int j=1;j<=n;j++)
    					if (i!=j && !check1(s,j) && !(line[i][j]&(~s)))
    						f[s|(1<<j-1)][j]=(f[s|(1<<j-1)][j]+f[s][i])%MOD;
    	for (rr int s=0;s<maxn;s++)
    		if (check3(s))
    			for (rr int i=1;i<=n;i++)	
    				if (check1(s,i)) ans=(ans+f[s][i])%MOD;
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    教你认识Git
    jmeter跨线程组传递token
    win10企业版激活步骤
    jmeter录制浏览器Https请求
    win10程序无法正常启动0xc0000142
    PPT页面切换动画
    PPT页面动画制作
    查询一门成绩高于另一门课程的学生信息
    MongoDB固定集合-capped collection
    CoronaSDK场景管理库:Composer library (中)
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998164.html
Copyright © 2011-2022 走看看