1. 程式人生 > >NOIP 2016 提高組 Day2 憤怒的小鳥

NOIP 2016 提高組 Day2 憤怒的小鳥

http://blog.csdn.net/u011056504/article/details/53367538

原理我懂了

注意到資料範圍:N<=18 
有什麼演算法? 
暴力?狀壓! 
狀壓DP,對於每隻豬1和0表示是否被打掉了 
設f[s]為當前狀態的最小步數 
我們知道,三個點可以確定一個拋物線 
已知一個點是原點,那麼再來兩個點就可以確定一個拋物線,設點i和點j確定的拋物線表示為(i,j) 
每次列舉一個狀態s,再列舉兩隻豬i,j,當然i,j不在s裡面 
那麼設所有經過(i,j)這條拋物線的點的集合為s’ 
那麼f[ss]=f[s]+1,f[0]=1 
那麼現在還需要預處理的就是每個集合s’ 
用a[i,j]存放拋物線(i,j)所經過的點的集合 
那麼轉移方程變成了 

f[sa[i,j](i,js)]=minf[sa[i,j](i,js)], f[s]+1),f[0]=1
時間複雜度O(2n+n2)

臨時程式碼,還要慢慢寫。

網上的程式碼。為什麼我的思路跟他一樣,但通過不呢??

#include <cmath>
#include <cstdio>
#include <cstring>
#define MAXN 20
using namespace std;
const double eps=1e-7;
struct Point
{
    double x,y;
    __attribute__((__optimize__("-O2"))) Point(){}
    __attribute__((__optimize__("-O2"))) Point(double x,double y):x(x),y(y){}
};
Point p[MAXN],res;
int n,m,T;
int dp[1<<MAXN];
int status[MAXN][MAXN];
double A,B,a,b;
__attribute__((__optimize__("-O2"))) inline double sqr(double x){return x*x;}
__attribute__((__optimize__("-O2"))) inline bool equal(double a,double b){return fabs(a-b)<eps;}
__attribute__((__optimize__("-O2"))) inline int mymin(int a,int b){return a<b?a:b;}
__attribute__((__optimize__("-O2"))) inline Point Solve(double a,double b,double c,double d,double e,double f)
{
    return Point((c*e-b*f)/(a*e-b*d),(a*f-c*d)/(a*e-b*d));
}
__attribute__((__optimize__("-O2"))) inline void MathProblem()
{
    memset(status,0,sizeof status);
    for (int i=1;i<=n;i++)
    {
        status[i][i]=1<<i-1;
        for (int j=i+1;j<=n;j++)
        {
            if (p[i].x==p[j].x&&p[i].y!=p[j].y) continue;
            res=Solve(p[i].x*p[i].x,p[i].x,p[i].y,p[j].x*p[j].x,p[j].x,p[j].y);
            A=res.x;B=res.y;
            if (equal(A,0.0)||A>=0.0) continue;
            status[i][j]=(1<<i-1)|(1<<j-1);
            for (int k=1;k<=n;k++)
                if (k!=i&&k!=j)
                {
                    if (p[i].x==p[k].x&&p[i].y!=p[k].y) continue;
                    res=Solve(p[i].x*p[i].x,p[i].x,p[i].y,p[k].x*p[k].x,p[k].x,p[k].y);
                    a=res.x;b=res.y;
                    if (equal(A,a)&&equal(B,b)) status[i][j]|=(1<<k-1);
                }
            status[j][i]=status[i][j];
        }
    }
    return ;
}
__attribute__((__optimize__("-O2"))) inline int Dynamic_Programming()
{
    memset(dp,0x7f,sizeof dp);dp[0]=0;
    for (int i=0;i<(1<<n)-1;i++)
        for (int j=1;j<=n;j++)
            for (int k=1;k<=n;k++)
                dp[i|status[j][k]]=mymin(dp[i|status[j][k]],dp[i]+1);
    return dp[(1<<n)-1];
}
__attribute__((__optimize__("-O2"))) int main()
{
    //freopen("angrybirds.in","r",stdin);freopen("angrybirds.out","w",stdout);
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d %d",&n,&m);
        for (int i=1;i<=n;i++) scanf("%lf %lf",&p[i].x,&p[i].y);
        MathProblem();
        printf("%d\n",Dynamic_Programming());
    }
    return 0;
}

我的程式碼 ,除錯的都要吐血了。沒有通過
#include <bits/stdc++.h>
//#define debug 1
using namespace std;
const int MM=18;
struct Point{
    double x;
    double  y;
};

vector<Point> p;
int dp[1<<MM];
int same[MM][MM];
int T,n,m;

bool check(double a, double b, Point pp){
    if( abs(  pp.y- a*pp.x*pp.x - b*pp.x  )<=1e-9 ) return  true;
        else  return false;
}


void math(){
    memset( same,0 ,sizeof(same) );
    for(int i=0;i<n;i++){
        for(int j=i+1; (j<n);j++){
            if(same[i][j]!=0) continue;
            //cout <<" i, j"<<i<<" "<<j;
            //int s=0;
            if(  ( p[i].x-p[j].x)==0.0  ) continue;
            double a = ( p[j].x * p[i].y -  p[i].x * p[j].y ) /( p[i].x * p[j].x *( p[i].x-p[j].x));
            double b =  ( p[i].y - a * p[i].x * p[i].x ) / p[i].x;

            #ifdef debug
                cout << "a , b :" <<a <<"  " <<  b <<endl;;
            #endif // debug

            if(a>0.0 || a<-1e-9) continue;
            //還沒有考慮到 兩個點只能確定開口向上的拋物線


            int s = 1<<i | 1<<j;
            for(int k=0;(k<n) ;k++)
                if( (k!=i) && (k!=j) && check(a,b,p[k] ) ) {
                     s = s | (1<<k);
                }
            same[i][j] = s;
           // cout << i << " "<<j <<"  "<<bitset<10>(same[i][j])<<endl;
            for(int dd=0; dd<n ;dd++){
                for(int ff=0;ff<n ;ff++){
                        if( (s>>dd&1) &&  (s>>ff & 1) && dd!=ff) {
                              same[dd][ff] = s;
                              same[ff][dd] =s;
                        }
                }
            }
            dp[s]=1;
        }
      }
      
      for(int i=0;i<n;i++){
         same[i][i] = 1<<i;         
      }

}

   

 #ifdef debug
      for(int dd=0;dd<n ;dd++){
                for(int ff=0;ff<n ;ff++){
                   cout << " i  j  same[i][j] " << dd<<" "<<ff<<" ::"<<bitset<10>( same[dd][ff]) << " ";
                }
                cout << endl;
            }
#endif // debug



int dprogram(){          
      dp[0]=0;
      for(int i=0;i<n;i++) dp[ 1<<i ] =1;    
      for(int i=0;i< (1<<n);i++) dp[i]=100000000;
      for(int s=0;s< 1<<n; s++){
            for(int i=0;i<n;i++){
                if( !( s>>i & 1) )   dp[ s | 1<<i ] =  min( dp[ s | 1<<i ], dp[s] + 1 );
                for(int j=i+1;j<n;j++){
                    if( !( s>>i & 1) &&  !( s>>j & 1)  ){
                        dp[ s | same[i][j] ] =  min( dp[ s | same[i][j] ], dp[s] + 1 );
                        //cout << bitset<10>(s) <<" " <<i <<" "<< j <<" " << bitset<10>( s| same[i][j] )<<"  "<< dp[s| same[i][j]] << endl;
                    }
                }
            }
        }

       return dp[(1<<n)-1] ;
}


int main(){

    cin >> T;
    while(T--){
        cin >> n>>m;
        p.clear();
        for(int i=0;i<n;i++){
            double a,b; cin>>a>>b;
            p.push_back((Point){a,b});
        }
        math();
        cout << dporgram();
   }
   
   return 0;
}