参考了大牛的博客
http://blog.csdn.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=0; i<a; i++) cin >> Member[i]; for(int i=0; i<m; i++) { cin >> P[i].num; for(int j=0; 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[0]; } for(int i=0; i<m; i++) { for(int j=0; j<i; j++) { G[i][j] = INF; if( Adj(P[i], P[j]) ) G[i][j] = 1; G[j][i] = G[i][j]; } G[i][i] = 0; } Floyd(); int ans = Slove(); cout << ans << endl; return 0; } void Floyd() { for(int k=0; k<m; k++) { for(int i=0; i<m; i++) { for(int j=0; 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=0; i< A.num; i++) { for(int j=0; j<B.num; j++) { if( (A.Point[i] == B.Point[j] && A.Point[i+1] == B.Point[j+1]) || (A.Point[i] == B.Point[j + 1] && A.Point[i+1] == B.Point[j]) ) return true; } } return false; } int Slove() { int index = 0, b[maxn]; for(int i=0; i<m; i++) { b[i] = CountPoint(i); } for(int i=1; i<m; i++) { if(b[i] < b[index]) index = i; } return b[index]; } int CountPoint(int k)//计算所有点 到达这个区域k 需要穿越多少条边 { int sum = 0; for(int i=0; i<a; i++) { int Min = INF; for(int j=0; j<m; j++) { if( P[j].vis[ Member[i] ] && Min > G[j][k] ) { Min = G[j][k]; } } sum += Min; } return sum; }