题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1827
思路:缩点后建新图,然后找入度为0的点,在入度为0的点中找颜色相同的最小的花费,将这些花费相加就是最后最小的花费了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<stack> 7 using namespace std; 8 #define MAXN 1111 9 #define inf 1<<30 10 vector<int>vet[MAXN]; 11 vector<int>map[MAXN]; 12 stack<int>S; 13 bool mark[MAXN]; 14 int color[MAXN]; 15 int to[MAXN];//入度 16 int dfn[MAXN],low[MAXN]; 17 int n,m,cnt,_count; 18 int cost[MAXN]; 19 20 void Tarjan(int u){ 21 dfn[u]=low[u]=++cnt; 22 mark[u]=true; 23 S.push(u); 24 for(int i=0;i<vet[u].size();i++){ 25 int v=vet[u][i]; 26 if(dfn[v]==0){ 27 Tarjan(v); 28 low[u]=min(low[u],low[v]); 29 }else if(mark[v]){ 30 low[u]=min(low[u],dfn[v]); 31 } 32 } 33 if(low[u]==dfn[u]){ 34 int v; 35 _count++; 36 do{ 37 v=S.top(); 38 S.pop(); 39 mark[v]=false; 40 color[v]=_count; 41 }while(u!=v); 42 } 43 } 44 45 int Solve(int u){ 46 int MIN=inf; 47 for(int i=1;i<=n;i++){ 48 if(color[i]==u&&cost[i]<MIN){ 49 MIN=cost[i]; 50 } 51 } 52 return MIN; 53 } 54 55 56 int main(){ 57 // freopen("1.txt","r",stdin); 58 int u,v,ans,count; 59 while(~scanf("%d%d",&n,&m)){ 60 for(int i=1;i<=n;i++){ vet[i].clear();map[i].clear(); } 61 for(int i=1;i<=n;i++)scanf("%d",&cost[i]); 62 for(int i=1;i<=m;i++){ 63 scanf("%d%d",&u,&v); 64 vet[u].push_back(v); 65 } 66 memset(mark,false,sizeof(mark)); 67 memset(dfn,0,sizeof(dfn)); 68 memset(low,0,sizeof(low)); 69 memset(color,0,sizeof(color)); 70 memset(to,0,sizeof(to)); 71 _count=cnt=0; 72 for(int i=1;i<=n;i++){ 73 if(dfn[i]==0)Tarjan(i); 74 } 75 for(int i=1;i<=n;i++){ 76 for(int j=0;j<vet[i].size();j++){ 77 if(color[i]!=color[vet[i][j]]){ 78 map[color[i]].push_back(color[vet[i][j]]); 79 to[color[vet[i][j]]]++; 80 } 81 } 82 } 83 count=ans=0; 84 for(int i=1;i<=_count;i++){ 85 if(to[i]==0){ 86 count++; 87 ans+=Solve(i); 88 } 89 } 90 printf("%d %d\n",count,ans); 91 } 92 return 0; 93 }