从9.13开始做强联通分量,开始强联通还把我给困住了,因为两个方程:
1、low[u]=min{low[u],low[v]}
2、low[u]=min{low[u],dfn[v]}
多看网上的讲解和图就晓得了:
其实第一个就是在每一次tarjan(u)之后,第二个就是在找到搜索过程中找到了根节点时;
例题:间谍网络
https://loj.ac/problem/10095
算是一道有难度的题了吧,反正在打完模板之外还要进行一遍dfs。需要思考的有三:
1、怎样判断能否控制完
2、可以全部控制时,怎样选最小费用
3、无法全部控制时,怎样选最小编号
分析:缩点,成了一个有向无环图,dfs每个强联通子图,找入度为0的图,当这个子图中有能控制的人时,累加上。若遇到这个子图中没有能贿赂的人时,依然要dfs进行完,最后在for循环判断出最小编号即可(当然之前要对能控制的点标记~)
对于问题2,其实已经解决了
#include<bits/stdc++.h> using namespace std; int n,p,r; struct node{ int to,next; }e[1100000]; int num=0,head[11000]; void add(int x,int y) { e[++num].to=y; e[num].next=head[x]; head[x]=num; } int fee[100000]; inline void read(int &x) { x=0;int f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=(x<<1)+(x<<3)+s-'0';s=getchar();} x*=f; } int dfn[10000],low[10000],co[10000],col,sta[10000],si[10000],top=0; int jin[10000],lian[100000],bz[100000]; void tarjan(int u) { low[u]=dfn[u]=++top; sta[top]=u; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else { if(!co[v]){ low[u]=min(low[u],dfn[v]); } } } if(low[u]==dfn[u]) { co[u]=++col; si[col]++; if(bz[u])lian[col]=u; while(sta[top]!=u) { if(bz[sta[top]]&&fee[sta[top]]<fee[lian[col]]) { lian[col]=sta[top]; } ++si[col]; co[sta[top]]=col; top--; } top--; } } int vis[100000]; void dfs(int u) { vis[u]=1; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(!vis[v]){ dfs(v); } } } int main() { for(int i=0;i<100000;i++) { lian[i]=4000; fee[i]=99999; } scanf("%d%d",&n,&p); for(int i=1;i<=p;i++) { int per,f; scanf("%d%d",&per,&f); bz[per]=1; fee[per]=f; } scanf("%d",&r); for(int i=1;i<=r;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); } for(int i=1;i<=n;i++) { if(!dfn[i])tarjan(i); } for(int i=1;i<=n;i++) { for(int j=head[i];j;j=e[j].next) { int v=e[j].to; if(co[i]!=co[v])jin[co[v]]++; } } bool flag=1; int ans=0; for(int i=1;i<=col;i++) { if(!jin[i]) { if(lian[i]!=4000) { ans+=fee[lian[i]]; dfs(lian[i]); } else{ flag=0; } } } if(flag) { printf("YES %d",ans); return 0; } for(int i=1;i<=n;i++) { if(!vis[i]){ printf("NO %d",i); return 0; } } }