hdu1827 強連通分量
阿新 • • 發佈:2020-09-06
hdu1827 Summer Holiday
傳送門
題意
給定一個\(n(1\leq n\leq 1000)\)個點,\(m(1\leq m\leq 2000)\)條邊的有向圖,每個點都有權值,選取一些點,使得這些點可以連線到圖中所有的點,計算總權值的最小值
題解
強連通分量縮點,將圖變成幾個\(DAG\),每個頂點的權值是它所代表的\(scc\)中所有點的權值最小值,在每個\(DAG\)中選擇所有入度為零的點,計算這些點的權值和
#include<iostream> #include<cstdio> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<cstring> #include<string> #include<sstream> #include<cmath> #include<ctime> #include<climits> #include<algorithm> #define LL long long #define PII pair<int,int> #define PLL pair<LL,LL> #define pi acos(-1.0) #define eps 1e-6 #define lowbit(x) x&(-x) using namespace std; const int maxn=1010,maxm=2010; int n,m,cost[maxn],dfn[maxn],low[maxn],scc[maxn],scccost[maxn],stk[maxn],top,dfscnt,scccnt; int in[maxn]; vector<int> g[maxn]; void tarjan(int u){ dfn[u]=low[u]=++dfscnt; stk[++top]=u; for(int v:g[u]){ if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(!scc[v]){ low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]){ scccnt++; while(1){ int v=stk[top--]; scc[v]=scccnt; scccost[scccnt]=min(scccost[scccnt],cost[v]); if(v==u) break; } } } int main(){ while(~scanf("%d%d",&n,&m)){ for(int i=1;i<=n;i++) scanf("%d",&cost[i]); for(int i=1;i<=n;i++) g[i].clear(); for(int i=0;i<m;i++){ int x,y; scanf("%d%d",&x,&y); g[x].push_back(y); } memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(scc,0,sizeof(scc)); memset(scccost,0x3f,sizeof(scccost)); memset(in,0,sizeof(in)); top=dfscnt=scccnt=0; for(int i=1;i<=n;i++){ if(!scc[i]) tarjan(i); } for(int i=1;i<=n;i++){ for(int v:g[i]){ if(scc[i]!=scc[v]) in[scc[v]]=1; } } int anscnt=0,ans=0; for(int i=1;i<=scccnt;i++){ if(!in[i]){ anscnt++; ans+=scccost[i]; } } printf("%d %d\n",anscnt,ans); } return 0; }