zoukankan      html  css  js  c++  java
  • POJ 2594 Treasure Exploration【传递闭包+最小路径覆盖】

    大意:

    有n个点,告诉你一些单向边,问多少条边能把所有的点覆盖【注意点能重复覆盖  比如4->1->2   5->3】

    分析:

    知识储备:

    传递闭包:  所谓传递,可以这么理解,对于节点j如果i能到k并且k能到j那么i能到j,这样用像floyed就能处理出任意两个点能否到达

    for(int k = 1; k <= n; k++) {
        for(int i = 1; i <= n; i++) {
            if(W[i][k]) {
                for(int j = 1; j <= n; j++) {
                    W[i][j] = W[i][j] || (W[i][k] && W[k][j]);
                }
            }
        }
    }

     

    由于点可以被重复利用所以用传递闭包处理处任意两点的到达关系

    在求最小路径覆盖就可以了。

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <vector>
     5 using namespace std;
     6 
     7 const int maxn = 505;
     8 const int INF = 1000000000;
     9 
    10 int n;
    11 int vis[maxn];
    12 int Link[maxn];
    13 vector<int> G[maxn];
    14 bool Find(int u) {
    15     for(int i = 0; i < G[u].size(); i++) {
    16         int v = G[u][i];
    17         if(!vis[v]) {
    18             vis[v] = 1;
    19             if(Link[v] == -1 || Find(Link[v])) {
    20                 Link[v] = u;
    21                 return true;
    22             }
    23         }
    24     }
    25     return false;
    26 }
    27 
    28 int solve() {
    29     memset(Link, -1, sizeof(Link));
    30     int cnt = 0;
    31     for(int i = 1; i <= n; i++) {
    32         if(G[i].size()) {
    33             memset(vis, 0, sizeof(vis));
    34             if(Find(i)) cnt++;
    35         }
    36     }
    37     return cnt;
    38 }
    39 
    40 int W[maxn][maxn];
    41 int main() {
    42     int m;
    43     int a, b;
    44     while(scanf("%d %d",&n, &m) && ( n + m) ) {
    45         for(int i = 1; i <= n; i++) G[i].clear();
    46         memset(W, 0, sizeof(W));
    47         while(m--) {
    48             scanf("%d %d",&a, &b);
    49             W[a][b] = 1;
    50         }
    51         for(int k = 1; k <= n; k++) {
    52             for(int i = 1; i <= n; i++) {
    53                 if(W[i][k]) {
    54                     for(int j = 1; j <= n; j++) {
    55                         W[i][j] = W[i][j] || (W[i][k] && W[k][j]);
    56                     }
    57                 }
    58             }
    59         }
    60         for(int i = 1; i <= n; i++) {
    61             for(int j = 1; j <= n; j++) {
    62                 if(W[i][j]) G[i].push_back(j);
    63             }
    64         }
    65         printf("%d
    ",n - solve());
    66     }
    67     return 0;
    68 }
    View Code
  • 相关阅读:
    Asp.net开发必备51种代码
    防止页面被多次提交
    c#发送邮件.net1.1和.net2.0中的两个方法
    鼠标移至小图,自动显示相应大图
    NET(C#)连接各类数据库集锦
    在C#中对XML的操作
    Window.ShowModalDialog使用总结
    SQLServer2005 添加用户,及操作权限
    定时器
    Global.asax.cs中的方法的含义
  • 原文地址:https://www.cnblogs.com/zhanzhao/p/3940434.html
Copyright © 2011-2022 走看看