luogu解题报告:P1262间谍网络【代码量惊人】【图论/强连通缩点】
分析
这个题一眼看上去并不难,似乎bfs就能解决问题,但事实上bfs只能解决第一问。第二问如何解决呢?首先要明确:强连通分量内如果有一个间谍被捕,所有人就会被捕,代价是其中所需金额最少的一个。因此可以进行强连通缩点,变成一个DAG。不难发现,金额最少就是DAG中所有入度为0的点的金额和。因为这些点非取不可,且取了就可以控制所有人。
然后就开始考验码农功了。。。。。对象的思想得到了运用。。
示例代码
#include <bits/stdc++.h>
using namespace std;
//#define DEBUG
/*basis of graph*/
class graph {
public:
struct p {
int to, next;
} edge[9005];
int head[3003], top;
int rank[3003];
int rd[3003];
graph()
{
memset(head, 0, sizeof head);
memset(rd, 0, sizeof rd);
memset(rank, 127/3, sizeof rank);
top = 0;
}
void edit_rank(int i, int j)
{
rank[i] = j;
}
void push(int i, int j)
{
edge[++top].to = j;
edge[top].next = head[i];
head[i] = top;
rd[j]++;
}
};
/* vars */
graph basic, reversed, solved;
int n, p, r;
int grp = 0;
/*kosaraju algorithm*/
int dfn[3005], t = 0, visited[3005], rank_g[3005];
int hash_tab[3005][3005];
void get_dfn(int i)
{
if (!visited[i]) {
visited[i] = 1;
for (int k = basic.head[i]; k; k = basic.edge[k].next)
get_dfn(basic.edge[k].to);
dfn[++t] = i;
}
}
void dfs(int i, int group)
{
#ifdef DEBUG
cout << "DEBUG DFS CALLED i = " << i << " ; group = " << group << endl;
#endif
visited[i] = group;
rank_g[group] = min(rank_g[group], basic.rank[i]);
for (int k = reversed.head[i]; k; k = reversed.edge[k].next)
if (!visited[reversed.edge[k].to])
dfs(reversed.edge[k].to, group);
}
/*work functions*/
// using by function::able & funcion::work
queue<int> que;
bool killed[3005];
bool able()
{
int count = 0;
for (int i = 1; i <= n; i++)
if (basic.rank[i] <= 233333333) {
que.push(i);
killed[i] = 1;
}
while (!que.empty()) {
int i = que.front();
que.pop();
count++;
for (int k = basic.head[i]; k; k = basic.edge[k].next) {
int to = basic.edge[k].to;
if (!killed[to]) {
killed[to] = 1;
que.push(to);
}
}
}
return count == n;
}
void view(const graph &g)
{
cout << "VIEWING GRAPH......" << endl;
int k;
cin >> k;
for (int i = 1; i <= n; i++) {
if (g.head[i])
cout << "." << i << endl;
for (int k = g.head[i]; k; k = g.edge[i].next)
cout << "--\t" << g.edge[k].to << endl;
}
cout << "Finish." << endl;
}
void work()
{
#ifdef DEBUG
view(basic);
view(solved);
#endif
if (!able()) {
cout << "NO" << endl;
for (int i = 1; i <= n; i++)
if (!killed[i]) {
cout << i << endl;
return;
}
}
int ans = 0;
for (int i = 1; i <= grp; i++)
if (solved.rd[i] == 0) {
#ifdef DEBUG
cout << i << endl;
#endif
ans += rank_g[i];
}
cout << "YES" << endl << ans << endl;
}
/*main function*/
int main() {
memset(visited, 0, sizeof visited);
memset(rank_g, 127/3, sizeof rank_g);
ios::sync_with_stdio(false);
cin >> n;
cin >> p;
for (int i = 1; i <= p; i++) {
int a, b;
cin >> a >> b;
basic.edit_rank(a, b);
}
cin >> r;
for (int i = 1; i <= r; i++) {
int a, b;
cin >> a >> b;
basic.push(a, b);
reversed.push(b, a);
}
/* main process for strong connected graph*/
for (int i = 1; i <= n; i++)
get_dfn(i);
memset(visited, 0, sizeof visited);
for (int i = t; i; i--)
if (!visited[dfn[i]])
dfs(dfn[i], ++grp);
#ifdef DEBUG
for (int i = 1; i <= n; i++)
cout << visited[i] << " ";
cout << endl;
#endif
memset(hash_tab, 0, sizeof hash_tab);
for (int i = 1; i <= n; i++)
for (int k = basic.head[i]; k; k = basic.edge[k].next) {
int to = basic.edge[k].to;
if (visited[to] != visited[i] && !hash_tab[visited[i]][visited[to]]) {
solved.push(visited[i], visited[to]);
hash_tab[visited[i]][visited[to]] = 1;
}
}
/* main work */
work();
return 0;
}
注:代码用vscode完成,果然优美2333.