您的位置:首页 > 理论基础 > 计算机网络

间谍网络(tarjan缩点)

2017-04-09 21:06 330 查看

洛谷传送门


看着这道题给人感觉就是tarjan求SCC,然而还得判断是否能控制全部间谍,这就得先从可以贿赂的点dfs一遍。

如果没有全部被标记了,就输出NO,再从没被标记的点里找最小的标号。

如果全被标记,就输出YES,再从入度为0的缩点里找最小的价格,加到ans中,最后输出ans。

——代码

 

#include <cstdio>
#include <stack>
#include <cstring>

using namespace std;

int n, p, r1, cnt, idx, ans = 30000001, minn;
int a[3001], next[8001], to[8001], head[3001], low[3001], dfn[3001], belong[3001], r[3001];
bool ins[3001], vis[3001], mey[3001];
stack <int> s;

inline void add(int x, int y)
{
to[cnt] = y;
next[cnt] = head[x];
head[x] = cnt++;
}

void dfs(int u)
{
int i, v;
vis[u] = 1;
mey[u] = 1;
for(i = head[u]; i != -1; i = next[i])
{
v = to[i];
if(!vis[v]) dfs(v);
}
}

void tarjan(int u)
{
low[u] = dfn[u] = ++idx;
s.push(u);
ins[u] = 1;
int i, v;
for(i = head[u]; i != -1; i = next[i])
{
v = to[i];
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(ins[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u])
{
cnt++;
do
{
v = s.top();
s.pop();
ins[v] = 0;
belong[v] = cnt;
}while(u != v);
}
}

int main()
{
int i, j, k, x, y, u, v;
scanf("%d %d", &n, &p);
for(i = 1; i <= p; i++)
{
scanf("%d", &x);
scanf("%d", &a[x]);
}
memset(head, -1, sizeof(head));
scanf("%d", &r1);
for(i = 1; i <= r1; i++)
{
scanf("%d %d", &x, &y);
add(x, y);
}
for(i = 1; i <= n; i++)
if(!vis[i] && a[i])
dfs(i);
for(i = 1; i <= n; i++)
if(!mey[i])
ans = min(ans, i);
if(ans != 30000001)
{
printf("NO\n%d", ans);
return 0;
}
cnt = 0;
for(i = 1; i <= n; i++)
if(!dfn[i])
tarjan(i);
for(u = 1; u <= n; u++)
for(i = head[u]; i != -1; i = next[i])
{
v = to[i];
if(belong[u] != belong[v]) r[belong[v]]++;
}
ans = 0;
for(i = 1; i <= cnt; i++)
if(r[i] == 0)
{
minn = 30000001;
for(j = 1; j <= n; j++)
if(belong[j] == i && a[j])
minn = min(minn, a[j]);
ans += minn;
}
printf("YES\n%d", ans);
return 0;
}
View Code

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: