题意:给定一些城市,若干成员在不同城市,城市间城墙相连,找一个区域,使成员集合时穿过的城墙最少。
分析:floyd+建图。以区域为节点,城墙为边建图。因为题目给定的包围区域的点是顺时针的,所以,如果区域a有边AB,区域b有边BA,那么a,b必相邻。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define MAX_N 255
#define MAX_M 205
#define MAX_L 35
#define inf 0x3f3f3f3f
using namespace std;
bool map[MAX_N][MAX_M];
int d[MAX_M][MAX_M];
int men[MAX_L];
int border[MAX_N][MAX_N];
int n,m,l;
void warshall_floyd(void)
{
for(int k=1;k<=m;k++)
{
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
void print(void)
{
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
printf("%16d",d[i][j]);
printf("\n");
}
}
int main(void)
{
while(scanf("%d%d%d",&m,&n,&l)==3)
{
memset(map,false,sizeof(map));
memset(border,-1,sizeof(border));
for(int i=0;i<l;i++)
scanf("%d",&men[i]);
for(int i=1;i<=m;i++)
{
int num;
scanf("%d",&num);
int a;
int pre;
int cur;
for(int j=0;j<num;j++)
{
scanf("%d",&cur);
map[cur][i]=true;
if(j==0)
{
a=cur;
pre=cur;
continue;
}
border[pre][cur]=i;
pre=cur;
}
border[cur][a]=i;
}
for(int i=1;i<=m;i++)
{
// d[i][i]=0;
for(int j=1;j<=m;j++)
{
if(i==j)
d[i][i]=0;
else
d[i][j]=inf;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
// if(i==j)
// continue;
if(border[i][j]!=-1)
{
int u=border[i][j];
int v=border[j][i];
d[u][v]=1;
}
}
}
warshall_floyd();
// print();
int ans=inf;
for(int i=1;i<=m;i++)
{
int sum=0;
for(int k=0;k<l;k++)
{
int t=inf;
for(int j=1;j<=m;j++)
{
if(map[men[k]][j])
t=min(t,d[j][i]);
}
sum+=t;
}
ans=min(ans,sum);
}
printf("%d\n",ans);
}
return 0;
}