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

tarjan——洛谷P1262 间谍网络

2017-06-02 13:27 197 查看
https://www.luogu.org/problem/show?pid=1262

好像很早以前就看懂啊这道题目了;

一直没做;

对于打出NO的,其实很简单:以每个指定的点为起始点做遍历,每到一个新的点就把计数器+1,最后比一下计数器数值与n的大小即可,如果打出NO则再进行一次爆扫即可。

那么如何处理计数器大小等于n,即打出YES的呢?

退一步思考,如果这个有向图是个DAG,怎么办?

这里只需要把所有入度为0的点的权值相加即可。(这一切都建立在能控制所有间谍的基础上)

因为如果不选用入度为0的点,那这些点就是无人控制的。

选了这些点之后,图也一定能被他们及他们的子孙控制,就是说其他备选的点不用选了。

那么好吧,怎么把一个带环有向图变成DAG?

#include<bits/stdc++.h>
using namespace std;
const int N=30005;
struct cs{int to,nxt;}a[200000];
int head
,ll;
int c
[2],tt
,q
,lin
,v
,A
,low
,p
,pp
;
bool in
;
int n,m,mm,x,y,t,nn,ans;
void init(int x,int y){
a[++ll].to=y;
a[ll].nxt=head[x];
head[x]=ll;
}
void dfs1(int x){
in[x]=1;
for(int k=head[x];k;k=a[k].nxt)
if(!in[a[k].to])dfs1(a[k].to);
}
void dfs(int x){
tt[x]=++t;low[x]=t;in[x]=1;q[++q[0]]=x;
for(int k=head[x];k;k=a[k].nxt){
if(!tt[a[k].to])dfs(a[k].to);
if(in[a[k].to])low[x]=min(low[x],low[a[k].to]);
}
if(low[x]==tt[x]){
v[++nn]=1e9;
while(1){
lin[q[q[0]]]
4000
=nn;
in[q[q[0]]]=0;
v[nn]=min(v[nn],p[q[q[0]]]);
if(q[q[0]--]==x)break;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
memset(p,63,sizeof p);
for(int i=1;i<=m;i++)scanf("%d%d",&x,&y),p[x]=y,pp[i]=x;
scanf("%d",&mm);
for(int i=1;i<=mm;i++){
scanf("%d%d",&x,&y);
init(x,y);
c[i][0]=x;c[i][1]=y;
}
for(int i=1;i<=m;i++)dfs1(pp[i]);
for(int i=1;i<=n;i++)
if(!in[i]){printf("NO\n%d",i);exit(0);} else in[i]=0;
for(int i=1;i<=n;i++)if(!tt[i])dfs(i);
for(int i=1;i<=mm;i++){
x=c[i][0];y=c[i][1];
if(lin[x]==lin[y])continue;
A[lin[y]]++;
}
for(int i=1;i<=nn;i++)if(!A[i])ans+=v[i];
printf("YES\n%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: