POJ 3660 Cow Contest (Floyd运用到传递闭包中~)

来源:互联网 发布:矩阵正规化 编辑:程序博客网 时间:2024/05/22 15:35

当时一直看不懂别人判断连通性的那句话,这里贴个别人的解释上来:

点击打开链接

在floyd-warshall(不了解该算法的点这里)求每对顶点间的最短路径算法中,可以通过O(v^3)的方法求出图的传递闭包。可以位每条边赋以权值1,然后运行Floyd-Wareshall。如果从  i  到  j  存在一条路径,则d(i,j)<N,否则d(i,j)=MAX。

一种改进的算法是:由于我们需要的只是判断是否从i到j存在一条通路,所以在Floyd-Wareshall中的动态规划比较中,我们可以把min和+操作改为逻辑or( ||  )和逻辑(&&)也就是将  d[i][j] = min(d[i][j],  d[i][k]+dist[k][j]);    改成    if(d[i][j] == 1 || (d[i][k] == 1 && d[k][j] == 1))   d[i][j] = 1;

设  d(i,j) = 1表示从 i 到 j 存在一条通路 p,且 p 的所有中间节点都在0,1,2,...,k中, 否则d(i,j)=0。我们把边(i,j)加入到E*中当且仅当d(i,j)=1。


然后我就知道是怎么回事了~~

#include <cstdio>#include <cstring>#define maxn 1010#define INF 0x3f3f3f3fint n, m, map[maxn][maxn];using namespace std;void floyd() {  for (int k = 1; k <= n; k++) {    for (int i = 1; i <= n; i++) {      for (int j = 1; j <= n; j++) {        map[i][j] = map[i][j] || (map[i][k] && map[k][j]); //判断图的连通性      }    }  }}int main(void) {  int x, y;  while (~scanf("%d", &n)) {    memset(map, 0, sizeof(map));    scanf("%d", &m);    for (int i = 1; i <= m; i++) {      scanf("%d%d", &x, &y);      map[x][y] = 1;    }    floyd();    int ans = 0;    for (int i = 1; i <= n; i++) { //对每个牛来说      int sum = 0;      for (int j = 1; j <= n; j++)        if (map[i][j] || map[j][i]) //意为牛i比的过的牛的数量加上比不过的          sum++;      if (sum ==          n - 1) //如果它与别人之间具有确定关系的数量之和为n-1说明它的名次确定        ans++;    }    printf("%d\n", ans);  }  return 0;}


原创粉丝点击