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; }