PS、正解貌似是状态压缩DP,DP依旧不会、感觉和售货员问题差不多,于是试了下模拟退火居然还真水过去了= =!
后然用状态压缩DP也写了一次、、、、、
CODE(1):模拟退火
/*模拟退火*/
/*AC代码:890ms*/
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <ctime>
#include <cmath>
#define min(a,b) (a<b?a:b)
#define RunN 70
#define RanN 70
#define INF 1e8
using namespace std;
struct Node
{
int link[25];
double len;
};
struct Node node[RanN+5];
double X[40],Y[40];
double ox,oy;
double map[40][40];
double dis[40];
double ans;
bool vis[40];
int N,cas;
void adjust(Node &now,int rn)//rn为调整次数
{
int i,u,v;
while(rn--)
{
u=rand()%(2*N)+1;
v=rand()%(2*N)+1;
if(u==v||now.link[u]==v) continue;
int du=now.link[u];
int dv=now.link[v];
now.link[u]=v;
now.link[v]=u;
now.link[du]=dv;
now.link[dv]=du;
}
double len=0;
memset(vis,false,sizeof(vis));
for(i=1;i<=2*N;i++)
{
if(vis[i]) continue;
v=now.link[i];
len+=map[i][v];
len+=min(dis[i],dis[v]);
vis[i]=vis[v]=true;
}
now.len=len;
}
void get_rnode()//产生RANN组初始数列
{
int i,j;
for(i=0;i<RanN;i++)
{
for(j=1;j<=N;j++)
{
node[i].link[j]=j+N;
node[i].link[j+N]=j;
}
adjust(node[i],N-1);//初始调整
}
}
void Run()
{
int i,j;
for(i=1;i<=2*N;i++)
{
map[i][i]=0;
for(j=i+1;j<=2*N;j++)
{
map[i][j]=map[j][i]=sqrt((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]));
}
}
for(i=1;i<=2*N;i++)
dis[i]=sqrt((X[i]-ox)*(X[i]-ox)+(Y[i]-oy)*(Y[i]-oy));
}
void Init()
{
int i,j;
scanf("%lf%lf",&ox,&oy);
scanf("%d",&N);
for(i=1;i<=2*N;i++)
scanf("%lf%lf",&X[i],&Y[i]);
Run();
get_rnode();
}
void Print()
{
int i;
printf("--------------\n");
for(i=0;i<RanN;i++)
printf("%.2lf\n",node[i].len);
printf("--------------\n");
}
void Solve()
{
int i,j,u,v,t=N-1;
Node temp;
//Print();
while(t--)
{
for(i=0;i<RanN;i++)
{
for(j=0;j<RunN;j++)
{
temp=node[i];
adjust(temp,t);
if(temp.len<node[i].len)
node[i]=temp;
}
}
}
double ans=INF;
for(i=0;i<RanN;i++)
{
if(ans>node[i].len)
ans=node[i].len;
}
printf("Case #%d: %.2lf\n",cas++,ans);
}
int main()
{
int T;
cas=1;
srand(time(0));
scanf("%d",&T);
while(T--)
{
Init();
Solve();
}
return 0;
}
CODE(2):状态压缩DP
/*状态压缩DP*/
/*AC代码:531ms*/
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <queue>
#include <cmath>
#define MAXN 2000000
#define INF 1e8
#define min(a,b) (a<b?a:b)
#define GOAL ((1<<(2*N))-1)
using namespace std;
int N,cas;
double X[30],Y[30];
double map[30][30];
double dis[30];
double ox,oy;
double dp[MAXN];
bool vis[MAXN];
int base[30];
void get_base()
{
int i;
base[0]=1;
for(i=1;i<30;i++)
base[i]=base[i-1]<<1;
}
void Run()
{
int i,j;
for(i=0;i<2*N;i++)
{
map[i][i]=0;
for(j=i+1;j<2*N;j++)
{
map[i][j]=map[j][i]=sqrt((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]));
}
}
for(i=0;i<2*N;i++)
dis[i]=sqrt((X[i]-ox)*(X[i]-ox)+(Y[i]-oy)*(Y[i]-oy));
for(i=0;i<MAXN;i++)
dp[i]=INF;
dp[0]=0;
}
void Init()
{
int i;
scanf("%lf%lf",&ox,&oy);
scanf("%d",&N);
for(i=0;i<2*N;i++)
scanf("%lf%lf",&X[i],&Y[i]);
Run();
}
//类似SPFA
queue<int>Q;
double BFS()
{
int i,u,pos,state;
double d;
memset(vis,false,sizeof(vis));
while(!Q.empty()) Q.pop();
Q.push(0);
vis[0]=true;
while(!Q.empty())
{
u=Q.front();Q.pop();
vis[u]=false;
pos=2*N;
for(i=0;i<2*N;i++)//先找到第一个为零的点,并固定下来
{
if((u&base[i])==0)
{pos=i;break;}
}
for(i=pos+1;i<2*N;i++)//然后O(N)扫描
{
if((u&base[i])==0)
{
d=dp[u]+map[pos][i]+min(dis[i],dis[pos]);
state=((u|base[pos])|base[i]);
if(dp[state]>d)
{
dp[state]=d;
if(!vis[state])
{
vis[state]=true;
Q.push(state);
}
}
}
}
}
return dp[GOAL];
}
void Print()
{
int i;
printf("%d\n",GOAL);
for(i=0;i<2*N;i++)
printf("%.2lf ",dis[i]);
printf("\n");
}
void Solve()
{
//Print();
double ans=BFS();
printf("Case #%d: %.2lf\n",cas++,ans);
}
int main()
{
int T;
cas=1;
get_base();
scanf("%d",&T);
while(T--)
{
Init();
Solve();
}
return 0;
}