//一个mtsp模型题,以前只弄过tsp,第一次弄mtsp,大牛的解题报告让我受益匪浅,mtsp问题主要就是对一个mtsp分解成多个单tsp组合,并使组合后取得的值是一个最值;
//代码如下:
#include<stdio.h> #include<string.h> #include<math.h> #define inf 10000000 struct node { int pre,sum,id; }list[200000]; int num[17],n,t; void find(int v) { struct node tem; int i,j,cnt=0,ant; for(i=1;i<=n;i++) { ant=cnt; for(j=1;j<=ant;j++) { tem.pre=j; tem.id=i; tem.sum=num[i]+list[j].sum; if(tem.sum<=v) list[++cnt]=tem; } tem.id=i; tem.pre=-1; tem.sum=num[i]; list[++cnt]=tem; } ant=0; for(i=1;i<=cnt;i++) { if(list[i].sum>ant) { ant=list[i].sum; j=i; } } while(j!=-1) { num[list[j].id]=-1; j=list[j].pre; } for(i=1,j=0;i<=n;i++) if(num[i]>0)num[++j]=num[i]; n=j; } struct nod { int x,y; }nod[20]; int get(int a,int b) { return (int)ceil(sqrt((nod[a].x-nod[b].x)*(nod[a].x-nod[b].x)+(nod[a].y-nod[b].y)*(nod[a].y-nod[b].y))); } int map[20][20],dp[100000][20],vis[100000],back[100000]; int ok(int k) { int sum=0,i; for(i=0;i<n;i++) if(k&1<<i) sum+=num[i+1]; return sum<=t; } int Min(int a,int b){return a<b?a:b;} int mtsp() { int i,j,k; for(k=0;k<n;k++) for(i=0;i<(1<<n);i++) dp[i][k]=inf; dp[1][0]=0; for(i=0;i<(1<<n);i++) { back[i]=inf; vis[i]=ok(i); } for(i=0;i<(1<<n);i++)//常规的状态压缩求单tsp的最优解 { if(vis[i]) { for(j=0;j<n;j++) { if(i&(1<<j)) { back[i]=Min(back[i],dp[i][j]+map[j+1][1]); for(k=0;k<n;k++) if(!(i&1<<k)) dp[i|1<<k][k]=Min(dp[i|1<<k][k],dp[i][j]+map[j+1][k+1]); } } } } for(i=0;i<(1<<n);i++)//下面这段组合代码是mtsp区别于tsp问题的地方,也是巧妙的地方 { if(i&1) { for(j=i&(i-1);j;j=i&(j-1))//最巧妙的地方是用这个j=i&(j-1)位运算来枚举所有子情况,很漂亮! back[i]=Min(back[i],back[j|1]+back[(i-j)|1]); } } return back[(1<<n)-1]; } int main() { int w,i,j,tem,flag,sum,cnt,ant; while(scanf("%d%d",&n,&t)!=EOF) { flag=1; sum=ant=0; for(i=1;i<=n;i++) scanf("%d%d",&nod[i].x,&nod[i].y); for(i=1;i<=n;i++) { scanf("%d",&num[i]); sum+=num[i]; if(num[i]>t)flag=0; } if(flag) { cnt=0; for(i=1;i<=n;i++) { for(j=i+1;j<=n;j++) { tem=get(i,j); map[i][j]=tem; map[j][i]=tem; } } tem=mtsp(); w=n; while(n) { cnt++; find(t); } n=w; printf("%d %d\n",cnt,tem); } else printf("-1 -1\n"); } return 0; }