hogloidのブログ

へなちょこ

PCK2013 予選 9

幾何ライブラリなくて焦ったけど大丈Vだった。

左端の取る点を固定して、反時計回りに取っていく。
dp[今までの頂点数][二つ前の頂点][一つ前の頂点]=面積最小値
とすると頑張って更新できる。O(N^5)
この値から、すべての答えをあらかじめ求めておく。
出力の順番を勘違いしてたので、ちょっと終盤頭悪いことになってます

#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<cstring>
#include<cstdio>
#include<complex>
 
#define REP(i,m) for(int i=0;i<m;++i)
#define REPN(i,m,in) for(int i=in;i<m;++i)
#define ALL(t) (t).begin(),(t).end()
#define fr first
#define sc second
#define pb push_back
#define mp make_pair
 
#define prl cerr<<__LINE__<<" is called"<<endl
#define dump(x) cerr<<#x<<" = "<<x<<endl
 
using namespace std;
template<class T> void debug(T a,T b){ for(;a!=b;++a) cerr<<*a<<' ';cerr<<endl;}
typedef pair<int,int> pi;
typedef long long lint;
typedef complex<lint> P;
const lint INF2=1e18;
 
P p[50],q[50];
int n;
bool cmp(const P& a,const P& b){
    if(a.real()!=b.real()) return a.real()<b.real();
    return a.imag()<b.imag();
}
lint cross(P a,P b){
    return a.real()*b.imag()-a.imag()*b.real();
}
int ccw(P a,P b,P c){
    b-=a;c-=a;
    if(cross(b,c)<0) return -1;//clockwise
    if(cross(b,c)>0) return 1;//counter-clockwise
    return 0;
}
 
lint getarea(P a,P b,P c){
    return abs(cross(b-a,c-a));
}
 
 
int id[55],rev[55];
lint minarea[55];
vector<int> vs[55];
lint dp[55][55][55];
int back[55][55][55];
void solve(int n,int add){
    REP(i,n+1) REP(j,n+1) REP(k,n+1) dp[i][j][k]=INF2;
    REPN(i,n,1) {
        dp[2][0][i]=0;
    }
 
    REP(i,n+1) REP(j,n) REP(k,n) if(dp[i][j][k]<INF2){
        REPN(l,n,1) if(j!=l && k!=l){
            if(ccw(q[j],q[k],q[l])==1 && ccw(q[k],q[l],q[0])>=0){
            lint nval=dp[i][j][k]+getarea(q[0],q[k],q[l]);
            if(dp[i+1][k][l]>nval){
                dp[i+1][k][l]=nval;
                back[i+1][k][l]=j;
            }
            }
        }
        if(minarea[i]>dp[i][j][k]){
            vector<int> tmp;
            tmp.pb(rev[k+add]);
            tmp.pb(rev[j+add]);
            int k2=k,j2=j,i2=i;
            while(j2!=0){
                int last=back[i2][j2][k2];
                k2=j2;
                j2=last;
                tmp.pb(rev[j2+add]);
                --i2;
            }
 
            minarea[i]=dp[i][j][k];
            reverse(ALL(tmp));
            vs[i]=tmp;
        }
    }
 
 
}
 
P prev[55];
int main(){
    cin>>n;
    REP(i,n) cin>>p[i].real()>>p[i].imag(),q[i]=prev[i]=p[i];
    REP(i,n+1) minarea[i]=INF2;
 
    sort(p,p+n,cmp);
    REP(i,n){
        REP(j,n) if(q[i]==p[j]) id[i]=j;
    }
    REP(i,n) rev[id[i]]=i;
    REP(i,n){
        REPN(j,n,i) q[j-i]=p[j]-p[i];
 
        solve(n-i,i);
    }
     
    REPN(s,n+1,3) if(minarea[s]!=INF2){
        REP(i,s){
            int fail=0;
            REP(j,s) if(prev[vs[s][i]].imag()>prev[vs[s][j]].imag() 
            || (prev[vs[s][i]].imag()==prev[vs[s][j]].imag() &&
                    prev[vs[s][i]].real()>prev[vs[s][j]].real())){
                fail=1;
            }
            if(!fail){
                rotate(vs[s].begin(),vs[s].begin()+i,vs[s].end());
                break;
            }
        }
    }
 
    int q;cin>>q;
    REP(hoge,q){
        int m;cin>>m;
        if(minarea[m]==INF2){
            puts("NA");
        }else{
            REP(j,m) printf("%d%c",vs[m][j]+1,j==m-1?'\n':' ');
        }
    }
 
    return 0;
}