• [luogu2831][noip d2t3]愤怒的小鸟_状压dp


    愤怒的小鸟 noip-d2t3 luogu-2831

        题目大意:给你n个点,问最少需要多少条经过原点的抛物线将其覆盖。

        注释:1<=点数<=18,1<=数据组数<=30。且规定抛物线是开口向下的。

          想法:其实一开始的想法是很偏的,就是设dp[i][j][k]表示在状态k下建立$i_{th}$和$j_{th}$的抛物线的最少条数,然后向后转移。这显然是错误的,错误原因在于... 我日,没个转移。然后看了一下lijinnn的题解...啊?切了。

          是这样的,我们通过记录每条抛物线所能覆盖的点,将其记录在数组str中,不分先后顺序。然后,我们考虑状态

            dp[s]表示达到s状态的最少条数。

          转移:

            dp[s]=min(dp[ s ] , dp[ s ^ ( s & str[ i ] ) ] + 1);

        最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    typedef double db;
    db ax[30],ay[30];
    int n,m;
    db ka,kb;
    int str[1000100],cnt,dp[300100];
    bool visit[1003000];
    void dispose(int x,int y)
    {
    	db tmp1=ax[x]*ax[y]*(ax[x]-ax[y]);//------------------------
    	db tmp2=ay[x]*ax[y]-ay[y]*ax[x];//                         |
    	if(tmp1<0)//                                               |
    	{//                                                        |
    		tmp1=-tmp1,tmp2=-tmp2;//                               |
    	}//                                                        |
    	if(fabs(tmp1)<1e-6)//                                      |
    	{//                                                        |
    	      return;//我们在计算过这两个点和原点的抛物线解析式       |
    	}//                                                        |
    	tmp1=tmp2/tmp1;//                                          |
    	if(tmp1>0)//                                               |
    	{//                                                        |
    		return;//                                              |
    	}//                                                        |
    	ka=tmp1;//                                                 |
    	kb=(ay[x]-ka*ax[x]*ax[x])/ax[x];//--------------------------
    	int s=0;
    	for(int i=1;i<=n;i++)//枚举所有的点,计算该点是否在当前枚举的抛物线之内
    	{
    		db tmp=ax[i]*ax[i]*ka+kb*ax[i];
    		if(fabs(tmp-ay[i])<1e-6)
    		{
    			s+=(1<<(i-1));
    		}
    	}
    	if(!visit[s])
    	{
    		visit[s]=1;
    		str[++cnt]=s;//统计出一条抛物线能够杀死的pig的状态
    	}
    	return;
    }
    void original()
    {
    	memset(visit,0,sizeof visit);
    	memset(dp,0x3f,sizeof dp);
    	cnt=0;
    }
    int main()
    {
    	int cases;
    	scanf("%d",&cases);
    	while(cases--)
    	{
    		original();
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%lf%lf",&ax[i],&ay[i]);
    		}
    		for(int i=1;i<=n;i++)
    		{
    			str[++cnt]=(1<<(i-1));
    			for(int j=1;j<=i-1;j++)
    			{
    				dispose(i,j);
    			}
    		}
    		dp[0]=0;
    		for(int s=0;s<(1<<n);s++)
    		{
    			for(int i=1;i<=cnt;i++)
    			{
    				if(s&str[i])
    				{
    					dp[s]=min(dp[s],dp[s^(s&str[i])]+1);//转移方程
    				}
    			}
    		}
    		printf("%d
    ",dp[(1<<n)-1]);
    	}
    	return 0;
    }
    

         小结:状态的选取决定着动态规划的走势----某乎上的dalao说的

  • 相关阅读:
    kvm介绍
    正式班D24
    正式班D23
    正式班D21
    正式班D20
    正式班D19
    正式班D18
    正式班D17
    正式班D16
    正式班D15
  • 原文地址:https://www.cnblogs.com/ShuraK/p/8600432.html
Copyright © 2020-2023  润新知