「AOJ2111~2120」の編集履歴(バックアップ)一覧に戻る
#include<stdio.h> #include<queue> #include<math.h> #include<string.h> struct State{ int nowNo,perm,r;//今いる地点と結んだ線分のリストのビット表現と次の向き double len;//今まで引いた長さ bool operator<(const State& s)const{ return len>s.len; } }; double memo[2][14][2<<14];//[次の線分の出発点][最後に結んだ線分][結んだ線のビット表現] bool first[2][14][2<<14];//最初 void setData(int n,int i){ double xs[2][15],ys[2][15]; memset(first,true,sizeof(first)); for(int i=0;i<n;i++){ scanf("%lf %lf %lf %lf",&xs[0][i],&ys[0][i],&xs[1][i],&ys[1][i]); } //printf("scanOK"); double lensMemo[2][2][15][15],len1;//線分で結ぶ時の距離のメモ for(int l1=0;l1<n;l1++){ for(int l2=0;l2<n;l2++){ if(l1==l2)continue;//同じ線分は結ばない for(int r1=0;r1<2;r1++){ for(int r2=0;r2<2;r2++){ len1=sqrt(pow(xs[r1][l1]-xs[r2][l2],2)+pow(ys[r1][l1]-ys[r2][l2],2)); lensMemo[r1][r2][l1][l2]=len1; } } } } //スタート地点となる線分のリストを作る std::priority_queue<State> pQ; State s,nextS; int ansPerm=0; s.len=0;//長さ0 for(int i=0;i<n;i++){ s.r=0;//どちらの両端から出発するか s.perm=(1<<i);//スタートの線分を使用禁止にする s.nowNo=i;//今いる線分 pQ.push(s); s.r=1;//逆の端から出発する pQ.push(s); ansPerm|=(1<<i);//答えの組み合わせを立てておく } double ansLen=0; for(int i=0;i<n;i++){ ansLen+=sqrt(pow(xs[0][i]-xs[1][i],2)+pow(ys[0][i]-ys[1][i],2)); } while(!pQ.empty()){ s=pQ.top(); pQ.pop(); if(s.perm==ansPerm)break;//答え到達 len1=memo[s.r][s.nowNo][s.perm]; if(first[s.r][s.nowNo][s.perm]==false&&len1<s.len)continue;//これより短い折れ線があった memo[s.r][s.nowNo][s.perm]=s.len; first[s.r][s.nowNo][s.perm]=false; for(int i=0;i<n;i++){ if((s.perm&(1<<i))!=0)continue;//この線分は接続済み nextS.perm=(s.perm|(1<<i)); nextS.nowNo=i; nextS.len=s.len+lensMemo[s.r][0][s.nowNo][i];//端点0と線分でつなげる nextS.r=1;//次は端点1からスタート len1=memo[nextS.r][nextS.nowNo][nextS.perm]; if(first[nextS.r][nextS.nowNo][nextS.perm]==true||len1>nextS.len){//より短いルートか初めて memo[nextS.r][nextS.nowNo][nextS.perm]=nextS.len; first[nextS.r][nextS.nowNo][nextS.perm]=false; pQ.push(nextS); } nextS.len=s.len+lensMemo[s.r][1][s.nowNo][i];//端点1と線分でつなげる nextS.r=0;//次は端点0から出発 len1=memo[nextS.r][nextS.nowNo][nextS.perm]; if(first[nextS.r][nextS.nowNo][nextS.perm]==true||(len1>nextS.len)){//より短いルートか初めてだった memo[nextS.r][nextS.nowNo][nextS.perm]=nextS.len; first[nextS.r][nextS.nowNo][nextS.perm]=false; pQ.push(nextS); } } } printf("Case %d: %.5lf\n",i,s.len+ansLen); } int main(){ int n,i=1; while(1){ scanf("%d",&n); if(n==0)break; setData(n,i); i++; } }
#include<stdio.h> #include<math.h> #include<string.h> #include<vector> #include<bitset> double memo[2][14][2<<14];//[次の線分の出発点][最後に結んだ線分][結んだ線のビット表現] bool first[2][14][2<<14];//最初 void setData(int n,int i){ double xs[2][15],ys[2][15]; memset(first,true,sizeof(first)); for(int i=0;i<n;i++){ scanf("%lf %lf %lf %lf",&xs[0][i],&ys[0][i],&xs[1][i],&ys[1][i]); } //printf("scanOK"); double lensMemo[2][2][15][15],len1;//線分で結ぶ時の距離のメモ for(int l1=0;l1<n;l1++){ for(int l2=0;l2<n;l2++){ if(l1==l2)continue;//同じ線分は結ばない for(int r1=0;r1<2;r1++){ for(int r2=0;r2<2;r2++){ len1=sqrt(pow(xs[r1][l1]-xs[r2][l2],2)+pow(ys[r1][l1]-ys[r2][l2],2)); lensMemo[r1][r2][l1][l2]=len1; } } } } //引かれてる線分の長さを集計しておく double ansLen=0; int ansPerm=0;//全部の線分を繋げた後の組み合わせ for(int i=0;i<n;i++){ ansLen+=sqrt(pow(xs[0][i]-xs[1][i],2)+pow(ys[0][i]-ys[1][i],2)); ansPerm|=(1<<i); memo[0][i][1<<i]=memo[1][i][1<<i]=0;//スタート地点の線分を設定 } int perm1,nextPerm; std::vector<int> perm[16];//結んだ線分の組み合わせ std::bitset<16> b; for(int i=1;i<(1<<n);i++){ b=i; perm[b.count()].push_back(i); } double nextLen,ans2=1000000000;; for(int i=1;i<n;i++){ for(int j=0;j<perm[i].size();j++){ perm1=perm[i][j];// for(int p1=0;p1<n;p1++){ if((perm1&(1<<p1))==0)continue;//この組み合わせは駄目 for(int p2=0;p2<n;p2++){ //線分p1からp2へと繋げる if((perm1&(1<<p2))!=0)continue;//これはもう繋げている if(p1==p2)continue;//あり得ないが念のため nextPerm=(perm1|(1<<p2)); for(int r1=0;r1<2;r1++){ for(int r2=0;r2<2;r2++){ nextLen=lensMemo[(r1+1)&1][r2][p1][p2]+memo[r1][p1][perm1]; //printf("%lf>",nextLen); if(first[r2][p2][nextPerm]==true){ first[r2][p2][nextPerm]=false; memo[r2][p2][nextPerm]=nextLen; }else if(memo[r2][p2][nextPerm]>nextLen){ memo[r2][p2][nextPerm]=nextLen; } if(nextPerm==ansPerm&&ans2>nextLen)ans2=nextLen; } } } } } } printf("Case %d: %.5lf\n",i,ansLen+ans2); } int main(){ int n,i=1; while(1){ scanf("%d",&n); if(n==0)break; setData(n,i); i++; } }