参考了大牛的博客
http://blog.****.net/wangjian8006/article/details/7958838
题目大意:
给出n个点,在这些点中有些点是俱乐部点,并且有m个区域是由点围成的
输入第一行代表n个点
第二行代表m个区域
第3行代表俱乐部有L个
第四行有L个数,分别标记哪些个点事是俱乐部
接下来2*m行,代表m个区域,每个区域由两行表示,第一行为区域由T个点围成的,
第二行T个数代表是哪些点围成这个区域,这些点按逆时针围成这个区域,相邻两点代表一条边
最后一点和第一点也是一条边,这样就是一个闭合的区域
现在问,在图中找出一个区域,使得所有俱乐部点到这个区域所要穿过的边之和最少,
输出最少的边数之和
题目思路:
建图 假如两个区域有公共边 则 两个区域的距离是 1, 然后 Floyd 求出所有区域的距离。
剩下的暴力解解决就OK了
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <cstring>
using namespace std;
#define INF 0xfffffff
#define maxn 260 struct Area
{
int num;
int Point[maxn];
bool vis[maxn];
} P[maxn]; int G[maxn][maxn], Member[maxn];
int n, m, a;//n个点 m个区域 a个座城有俱乐部成员 void Floyd();
bool Adj(Area A, Area B);
int Slove();
int CountPoint(int k); int main()
{
cin >> m >> n >> a; for(int i=; i<a; i++)
cin >> Member[i]; for(int i=; i<m; i++)
{
cin >> P[i].num; for(int j=; j<P[i].num; j++)
{
cin >> P[i].Point[j];
P[i].vis[ P[i].Point[j] ] = true;
} P[i].Point[P[i].num] = P[i].Point[];
} for(int i=; i<m; i++)
{
for(int j=; j<i; j++)
{
G[i][j] = INF;
if( Adj(P[i], P[j]) )
G[i][j] = ; G[j][i] = G[i][j];
}
G[i][i] = ;
} Floyd(); int ans = Slove(); cout << ans << endl; return ;
}
void Floyd()
{
for(int k=; k<m; k++)
{
for(int i=; i<m; i++)
{
for(int j=; j<m; j++)
{
if(G[i][j] > G[i][k] + G[k][j] )
{
G[i][j] = G[i][k] + G[k][j];
}
}
}
}
} bool Adj(Area A, Area B)
{
for(int i=; i< A.num; i++)
{
for(int j=; j<B.num; j++)
{
if( (A.Point[i] == B.Point[j] && A.Point[i+] == B.Point[j+]) ||
(A.Point[i] == B.Point[j + ] && A.Point[i+] == B.Point[j]) )
return true;
}
}
return false;
} int Slove()
{
int index = , b[maxn];
for(int i=; i<m; i++)
{
b[i] = CountPoint(i);
} for(int i=; i<m; i++)
{
if(b[i] < b[index])
index = i;
}
return b[index];
} int CountPoint(int k)//计算所有点 到达这个区域k 需要穿越多少条边
{
int sum = ; for(int i=; i<a; i++)
{
int Min = INF;
for(int j=; j<m; j++)
{
if( P[j].vis[ Member[i] ] && Min > G[j][k] )
{
Min = G[j][k];
}
}
sum += Min;
}
return sum;
}