【洛谷1262】间谍网络

tarjan缩点后找入度为零的强连通分量,加上它的sum即可

但注意到还有NO的可能,

所以大致有两种方法:

1.tarjan之前先来一遍bfs

2.tarjan内加一个数组维护最小编号

貌似前者比较好写qwq

  1 #include<cstdio>
  2 #include<cstring>
  3 using namespace std;
  4 const int N=3010,M=6020;
  5 const int novis=-1,nowvis=1,over=0;
  6 int value[N],sum[N],flag[N],vis[N],que[M],n;
  7 int head[M],next[M],to[M],size;
  8 int low[N],dfn[N],color[N],in[N],sig,cnt,top;
  9 void bfs(int),uni(int,int),tarjan(),dfs(int),rebuild();
 10 int min(int,int);
 11 int main(){
 12     int x,y,p,r,tmp,ans;
 13     ans=size=0;
 14     memset(vis,0,sizeof(vis));
 15     memset(sum,0,sizeof(sum));
 16     memset(flag,0,sizeof(flag));
 17     memset(in,0,sizeof(in));
 18     scanf("%d %d",&n,&p);
 19     for (int i=1;i<=n;i++)
 20         value[i]=10000001;//初始化最大值便于后面sum取min
 21     for (int i=1;i<=p;i++){
 22         scanf("%d %d",&x,&y);
 23         value[x]=y;
 24         flag[x]=1;
 25     }  
 26     scanf("%d",&r);
 27     for (int i=1;i<=r;i++){
 28         scanf("%d %d",&x,&y);
 29         uni(x,y);
 30     }
 31     for (int i=1;i<=n;i++)
 32         if (!vis[i]) bfs(i);
 33     for (int i=1;i<=n;i++)
 34         if (!vis[i]&&!flag[i]){
 35             printf("NO\n%d",i);
 36             return 0;
 37         }
 38     tarjan(); 
 39     for (int i=1;i<=cnt;i++)
 40         if (!in[i]) ans+=sum[i];
 41     printf("YES\n%d",ans);
 42     return 0;
 43 }
 44 void uni(int x,int y){
 45     size++;
 46     next[size]=head[x];
 47     head[x]=size;
 48     to[size]=y;
 49 }
 50 void bfs(int x){
 51     int r,l,u,v;
 52     l=0;r=1;que[1]=x;
 53     while (l<=r){
 54         u=que[++l];
 55         for (int e=head[u];e;e=next[e]){
 56             v=to[e];
 57             if (!vis[v]) que[++r]=v;
 58             vis[v]=1;
 59         }
 60     }
 61 }
 62 void tarjan(){
 63     memset(flag,novis,sizeof(flag));
 64     sig=cnt=top=0;
 65     for (int i=1;i<=n;i++)
 66         if (flag[i]==novis) dfs(i);
 67     rebuild();
 68 }
 69 void dfs(int x){
 70     que[++top]=x;
 71     flag[x]=nowvis;
 72     low[x]=dfn[x]=++sig;
 73     for (int e=head[x];e;e=next[e]){
 74         int y=to[e];
 75         if (flag[y]==novis){
 76             dfs(y);
 77             low[x]=min(low[x],low[y]);
 78         }
 79         else if (flag[y]==nowvis)
 80             low[x]=min(low[x],dfn[y]);
 81     }
 82     if (low[x]==dfn[x]){
 83         cnt++;int t;
 84         if (!sum[cnt]) sum[cnt]=20001; 
 85         do{
 86             t=que[top--];
 87             flag[t]=over;
 88             color[t]=cnt;
 89             sum[cnt]=min(sum[cnt],value[t]);
 90         }while (t!=x);
 91     }
 92 }
 93 void rebuild(){//入度  
 94     for (int u=1;u<=n;u++)
 95         for (int e=head[u];e;e=next[e]){
 96             int v=to[e];
 97             if (color[u]!=color[v]) 
 98                 in[color[v]]++;
 99         }
100 }
101 int min(int x,int y){
102     return x<y?x:y;
103 }
STD

 

转载于:https://www.cnblogs.com/Absolute-Zero/p/5876727.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值