很好的建图题,有点繁琐,但是挺有意思的,我想了好久,中间有不少想法,敲出来一个,发现是错的,从头再敲,然后再敲出来一个,发现还不对,discuss里面有人说 BFS 神马的,我没往那方面想,一直用 floyd 加上枚举建图,最后终于A掉了……
YM我自己一下……
(笑吧,不过别让我知道……)
题意是说有 n 个小镇,他们两两之间可能存在一些墙(不是每两个都有),把整个二维平面分成多个区域,当然这些区域都是一些封闭的多边形(除了最外面的一个),现在,如果某几个小镇上的人想要聚会,为选择哪个区域为聚会地点,可以使他们所有人总共需要穿过的墙数最小,题目上有说明,不在某个点上聚会(聚会点在某个多边形内部),行进过程中不穿过图中的点(也就是除出发点外的其他小镇)。
思路:
每个人的出发点一定属于某个环(多边形),两个相邻环之间要想通行的话,穿过一面墙就可以直接到达,如果不相邻的话,需要先穿过其他区域间接到达。这样,一个最短路模型就出来了。
把每个环当成点,以两个环之间的距离为边建图,相邻环之间距离为 1 ,不相邻的先设为无穷大,然后 floyd 暴搞,最后枚举每个区域到所有人的距离之和,找到那个合适的区域就可以了。
代码:
#include<stdio.h> #include<string.h> #define Ni 300 #define MAX 99999999 #define min(a,b) a<b?a:b int map[Ni][Ni],region[Ni][Ni],p_num[Ni],n,m,r; struct Person { int adr; int t;//在几个区域(环)中出现过 int reg[Ni];//都在哪几个区域中出现过 }person[Ni]; int find_dis(int i,int j)//第 i 个区域到第 j 个区域的距离 { int ii,jj; for(ii=1;ii<=p_num[i];ii++) { for(jj=1;jj<=p_num[j];jj++) if(region[i][ii]==region[j][jj]) { if(region[i][ii+1]==region[j][jj+1] || region[i][ii+1]==region[j][jj-1] || region[i][ii-1]==region[j][jj+1] || region[i][ii-1]==region[j][jj-1]) return 1; } } return -1; } void floyd() { int i,j,k; for(k=1;k<=m;k++) { for(i=1;i<=m;i++) for(j=1;j<=m;j++) map[i][j]=map[j][i]=min(map[i][j],map[i][k]+map[k][j]); } } int search(int i)//第 i 个区域到所有人的距离之和的最小值 { int j,k,s=0; for(j=1;j<=r;j++) { int d=MAX; for(k=1;k<=person[j].t;k++) d=min(d,map[ person[j].reg[k] ][i]); s+=d; } return s; } int main() { int i,j,k; while(~scanf("%d",&m)) { scanf("%d",&n); scanf("%d",&r); for(i=1;i<=r;i++) { scanf("%d",&person[i].adr); person[i].t=0; } for(i=1;i<=m;i++) { scanf("%d",&p_num[i]); for(j=1;j<=p_num[i];j++) { scanf("%d",®ion[i][j]); for(k=1;k<=r;k++) { if(person[k].adr==region[i][j]) person[k].reg[ ++person[k].t ]=i; } } region[i][0]=region[i][ p_num[i] ]; region[i][ p_num[i]+1 ]=region[i][1]; } for(i=1;i<=m;i++)//把区域看成点,计算每两个区域之间的距离,相邻为1,否则为MAX { for(j=1;j<=m;j++) { if(i==j) { map[i][j]=map[j][i]=0;continue; } int ans=find_dis(i,j); if(ans==1) map[i][j]=map[j][i]=1; else map[i][j]=map[j][i]=MAX; } } floyd(); int min_dis=search(1); for(i=2;i<=m;i++)//枚举每个区域,到所有人的距离之和的最小值 { int d=search(i); min_dis=min(d,min_dis); } printf("%d/n",min_dis); } return 0; }