http://blog.youkuaiyun.com/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)所经过的点的集合
那么转移方程变成了
f[s⋁a[i,j](i,j不∈s)]=min( f[s⋁a[i,j](i,j不∈s)], 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;
}