Walls POJ 1161

参考了大牛的博客 

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;

}

 

你可能感兴趣的:(poj)