loj 1429(可相交的最小路径覆盖)

题目链接:http://lightoj.com/volume_showproblem.php?problem=1429

思路:这道题还是比较麻烦的,对于求有向图的可相交的最小路径覆盖,首先要解决成环问题,可以先染色缩点重建图,然后就是如何来处理这个路径可以相交这个问题,这里可以用bfs求出任意两点之间是否可达,如果可达,就连边,然后就是HK算法求最大匹配了,最小路径覆盖 = 顶点数 - 最大匹配。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <queue>
  7 #include <stack>
  8 using namespace std;
  9 
 10 const int MAXN = (1000 + 10);
 11 const int MAXM = (10000 + 10);
 12 int n, m;
 13 int cnt, scc_count;
 14 bool Instack[MAXN];
 15 int low[MAXN], dfn[MAXN], color[MAXN];
 16 vector<int > g[MAXN];
 17 stack<int > S;
 18 
 19 void Tarjan(int u)
 20 {
 21     low[u] = dfn[u] = ++cnt;
 22     Instack[u] = true;
 23     S.push(u);
 24     for (int i = 0; i < (int)g[u].size(); i++) {
 25         int v = g[u][i];
 26         if (dfn[v] == 0) {
 27             Tarjan(v);
 28             low[u] = min(low[u], low[v]);
 29         } else if (Instack[v]) {
 30             low[u] = min(low[u], dfn[v]);
 31         }
 32     }
 33     if (low[u] == dfn[u]) {
 34         scc_count++;
 35         int v;
 36         do {
 37             v = S.top();
 38             S.pop();
 39             Instack[v] = false;
 40             color[v] = scc_count;
 41         } while (u != v);
 42     }
 43 }
 44 
 45 bool Isok[MAXN][MAXN];
 46 bool mark[MAXN];
 47 vector<int > reg[MAXN];
 48 
 49 void bfs(int st)
 50 {
 51     memset(mark, false, sizeof(mark));
 52     queue<int >que;
 53     que.push(st);
 54     mark[st] = true;
 55     while (!que.empty()) {
 56         int u = que.front();
 57         que.pop();
 58         for (int i = 0; i < (int)reg[u].size(); i++) {
 59             int v = reg[u][i];
 60             if (!mark[v]) {
 61                 mark[v] = true;
 62                 que.push(v);
 63             }
 64         }
 65     }
 66 }
 67 
 68 void Build()
 69 {
 70     for (int i = 1; i <= scc_count; i++) {
 71         reg[i].clear();
 72     }
 73     for (int i = 1; i <= scc_count; i++) {
 74         for (int j = 1; j <= scc_count; j++) {
 75             if (i != j && Isok[i][j]) {
 76                 reg[i].push_back(j);
 77             }
 78         }
 79     }
 80 }
 81 
 82 int lx[MAXN], ly[MAXN];
 83 int distx[MAXN], disty[MAXN];
 84 
 85 bool MaxMatch_bfs()
 86 {
 87     bool flag = false;
 88     memset(distx, 0, sizeof(distx));
 89     memset(disty, 0, sizeof(disty));
 90     queue<int > que;
 91     for (int i = 1; i <= scc_count; i++) {
 92         if (lx[i] == -1) que.push(i);
 93     }
 94     while (!que.empty()) {
 95         int u = que.front();
 96         que.pop();
 97         for (int i = 0; i < (int)reg[u].size(); i++) {
 98             int v = reg[u][i];
 99             if (disty[v] == 0) {
100                 disty[v] = distx[u] + 1;
101                 if (ly[v] == -1) flag = true;
102                 else {
103                     distx[ly[v]] = disty[v] + 1;
104                     que.push(ly[v]);
105                 }
106             }
107         }
108     }
109     return flag;
110 }
111 
112 int dfs(int u)
113 {
114     for (int i = 0; i < (int)reg[u].size(); i++) {
115         int v = reg[u][i];
116         if (disty[v] == distx[u] + 1) {
117             disty[v] = 0;
118             if (ly[v] == -1 || dfs(ly[v])) {
119                 ly[v] = u;
120                 lx[u] = v;
121                 return 1;
122             }
123         }
124     }
125     return 0;
126 }
127 
128 int MaxMatch()
129 {
130     memset(lx, -1, sizeof(lx));
131     memset(ly, -1, sizeof(ly));
132     int res = 0;
133     while (MaxMatch_bfs()) {
134         for (int i = 1; i <= scc_count; i++) {
135             if (lx[i] == -1) res += dfs(i);
136         }
137     }
138     return res;
139 }
140 
141 
142 int main()
143 {
144     int _case, t = 1;
145     scanf("%d", &_case);
146     while (_case--) {
147         scanf("%d %d", &n, &m);
148         for (int i = 1; i <= n; i++) {
149             g[i].clear();
150             reg[i].clear();
151         }
152         while (m--) {
153             int u, v;
154             scanf("%d %d", &u, &v);
155             g[u].push_back(v);
156         }
157         //强联通缩点重建图
158         cnt = scc_count = 0;
159         memset(dfn, 0, sizeof(dfn));
160         for (int i = 1; i <= n; i++) {
161             if (dfn[i] == 0) Tarjan(i);
162         }
163         for (int u = 1; u <= n; u++) {
164             for (int i = 0; i < (int)g[u].size(); i++) {
165                 int v = g[u][i];
166                 if (color[u] != color[v]) {
167                     reg[color[u]].push_back(color[v]);
168                 }
169             }
170         }
171         //bfs求出新图中的任意两点之间是否可达
172         memset(Isok, false, sizeof(Isok));
173         for (int i = 1; i <= scc_count; i++) {
174             bfs(i);
175             for (int j = 1; j <= scc_count; j++) {
176                 if (mark[j]) {
177                     Isok[i][j] = true;
178                 }
179             }
180         }
181         //对于那些可达的点重新连边
182         Build();
183         //bfs求解最大匹配;
184         //最小路径覆盖 = 顶点数 - 最大匹配数
185         int ans = MaxMatch();
186         printf("Case %d: %d
", t++, scc_count- ans);
187     }
188     return 0;
189 }
View Code
原文地址:https://www.cnblogs.com/wally/p/3532663.html