NOIP 2016 提高組 Day2 憤怒的小鳥
阿新 • • 發佈:2019-02-03
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[s⋁s′]=f[s]+1,f[0]=1
那麼現在還需要預處理的就是每個集合s’
用a[i,j]存放拋物線(i,j)所經過的點的集合
那麼轉移方程變成了
時間複雜度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; }