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

间谍网络 洛谷 1262 强连通分量

2017-01-13 12:59 288 查看

题目大意

给你一些点,再指定其中的一部分点并加上权值,问是否有一种方案,使得从指定的点中的某几个点开始对图遍历,能把整个图遍历完,并且权值最小。

分析

tarjan缩点。

对于每一个强连通分量,我们就要那个权值最小作为权值即可。

缩完点后构图,统计入度。

如果一个强连通分量的入度为0且里面没有点有权值,那就输出no。

不然,每个入度为0的强连通分量的权值和就是答案。。。

code

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>

using namespace std;

struct arr{
int x,y,w,next;
}edge[1000000];
int ls[10000];
int edge_m;

int s[10000];
int n,m,r;

int a[10000];
void add(int x,int y)//加边。
{
edge[++edge_m]=(arr){x,y,1,ls[x]},ls[x]=edge_m;
return;
}

int v[10000];
int dfn[10000];
int low[10000];
int scc[10000];
int small[10000];
int ans=0;

int num=0;
stack<int> sta;

void tarjan(int x)//tarjan求强连通分量。
{
sta.push(x);
num++;
dfn[x]=low[x]=num;
v[x]=1;

for (int i=ls[x];i;i=edge[i].next)
{
int y=edge[i].y;
if (dfn[y]==0)
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else
if (v[y]) low[x]=min(dfn[y],low[x]);
}
if (dfn[x]==low[x])
{
ans++;
while ((sta.top()!=x)&&(!sta.empty()))
{
int y=sta.top();
v[y]=0;
scc[y]=ans;
small[ans]=min(small[ans],a[y]);
sta.pop();
}
int y=sta.top();
v[y]=0;
scc[y]=ans;
small[ans]=min(small[ans],a[y]);
sta.pop();
}
}

int main()
{
scanf("%d",&n);
scanf("%d",&r);
memset(a,63,sizeof(a));
memset(small,63,sizeof(small));

for (int i=1;i<=r;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[x]=y;
}

scanf("%d",&m);

for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}

for (int i=1;i<=n;i++)
if (dfn[i]==0)
tarjan(i);

for (int i=1;i<=m;i++)//统计各个强连通分量的入度。
{
int x=edge[i].x;
int y=edge[i].y;
if (scc[x]!=scc[y])
s[scc[y]]++;
}

for (int i=1;i<=n;i++)
if ((s[scc[i]]==0)&&(small[scc[i]]==small[0]))
{
printf("NO\n"),printf("%d",i);
return 0;
}

printf("YES\n");
int la=0;
for (int i=1;i<=ans;i++)
if (s[i]==0) la+=small[i];
printf("%d",la);

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