HDU - 1827 Summer Holiday (强连通)

时间:2021-08-19 09:18:53

<题目链接>

题目大意:

听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间和电话费了。他知道其他人也有一些别人的联系方式,这样他可以通知其他人,再让其他人帮忙通知一下别人。你能帮Wiskey计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗?

解题分析:

强连通缩点,再将所有入度为0的强连通分量中最小的价值相加即可。

#include <bits/stdc++.h>
using namespace std; #define pb push_back
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define clr(a,b) memset(a,b,sizeof(a))
const int N = 1e3+,M = 2e3+;
int n,m,tot,cnt,scc,top;
int val[N],instk[N],stk[N],dfn[N],low[N],ind[N],outd[N],belong[N],head[N];
struct Edge{
int to,next;
}edge[M];
vector<int>G[N];
void init(){
rep(i,,n)G[i].clear();
tot=cnt=scc=top=;
clr(instk,);clr(stk,);clr(dfn,);clr(low,);clr(ind,);clr(outd,);clr(belong,),clr(head,-);
}
void addedge(int u,int v){
edge[++cnt].to=v,edge[cnt].next=head[u];
head[u]=cnt;
}
void Tarjan(int u){
dfn[u]=low[u]=++tot;
stk[++top]=u;instk[u]=;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}else if(instk[v])low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
scc++;
while(true){
int v=stk[top--];
instk[v]=;
belong[v]=scc;
G[scc].pb(v);
if(v==u)break;
}
}
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
init();
rep(i,,n)scanf("%d",&val[i]);
rep(i,,m){
int u,v;scanf("%d%d",&u,&v);
addedge(u,v);
}
rep(i,,n)
if(!dfn[i])Tarjan(i);
rep(u,,n) for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(belong[u]!=belong[v])
ind[belong[v]]++,outd[belong[u]]++;
}
int ans=,res=;
rep(i,,scc) if(!ind[i]){
int mn=1e9;
rep(j,,G[i].size()-){ //遍历该连通块中的所有元素,寻找价值最小的
int v=G[i][j];
mn=min(mn,val[v]);
}
res++;
ans+=mn;
}
printf("%d %d\n",res,ans);
}
}