1 #include<cstdio> 2 #include<iostream> 3 #define MAX 0xfffffff 4 using namespace std; 5 int m,l; 6 int Area[201][251],G[201][201],People[251],Dist[31]; 7 int Init()//初始化数据 8 { 9 int i,j,k,t; 10 for(i=1;i<=l;++i) 11 { 12 scanf("%d",&t); 13 People[t]=i; 14 } 15 for(i=1;i<=m;++i) 16 for(j=1;j<=m;++j) 17 if(i!=j) 18 G[i][j]=MAX; 19 for(i=1;i<=m;++i) 20 { 21 scanf("%d",&Area[i][0]); 22 for(j=1;j<=Area[i][0];++j) 23 scanf("%d",&Area[i][j]); 24 Area[i][j]=Area[i][1];//记得区域是封闭的,所以加了这点 25 for(j=1;j<=Area[i][0];++j) 26 for(k=1;k<i;++k) 27 for(t=1;t<=Area[k][0];++t) 28 if(Area[i][j]==Area[k][t+1]&&Area[i][j+1]==Area[k][t])//判断两块区域是否相邻 29 G[i][k]=G[k][i]=1; 30 } 31 } 32 int Solve() 33 { 34 int i,j,k,t,sum=MAX; 35 for(k=1;k<=m;++k)//Floyd求所有点之间的最短路径,也即是需要翻越的墙数 36 for(i=1;i<=m;++i) 37 for(j=1;j<=m;++j) 38 G[i][j]=min(G[i][j],G[i][k]+G[k][j]); 39 for(k=1;k<=m;++k)//枚举以每一块区域作为聚集块 40 { 41 for(i=1;i<=l;++i) 42 Dist[i]=MAX; 43 for(i=1;i<=m;++i) 44 for(j=1;j<=Area[i][0];++j) 45 if(People[Area[i][j]]>0&&Dist[People[Area[i][j]]]>G[k][i])//每个人到第k块的最短路径 46 Dist[People[Area[i][j]]]=G[k][i]; 47 for(t=0,i=1;i<=l;++i)//求总和 48 t+=Dist[i]; 49 if(sum>t) sum=t;//更新sum 50 } 51 return sum; 52 } 53 int main() 54 { 55 while(~scanf("%d%*d%d",&m,&l)){//n没有用,直接跳过 56 Init(); 57 printf("%d\n",Solve()); 58 } 59 return 0; 60 }
题意很简单,很容易理解,但是题目只告诉了我们一个地区是由几个顶点组成的这个条件,并没有告诉我们一个地区到另一个地区需要经过几道墙。所以问题的重点就是将已知的图转化成我们所需要的图。
因为题中一块区域周围的点都是按顺时针给出的,所以要判断两个区域是否相邻的时候,首先找到区域A中的某个点a1,如果区域B的周围也有a1,此时,比较A区域中a1的后继与B区域中a1的前继或者A区域中a1的前继与B区域中a1的后继是否相同,如果相同,两个区域便是相邻的。即在邻接表中,A到B的权值是1。
老师留的是并查集的作业,貌似本题用不上并查集!!!