hdu 3639(强连通+缩点+建反向图)+hdu 3072(最小树形图)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3639

思路:先按一般的思路来,把杂乱的有向图通过缩点变成有向无环图,然后建反向图,并标记每个点的入度(最大值一定在反向图的入度为的点中)然后dfs一下下就可以了,最后就是在原图中找等于MAX的点就可以了。

View Code
  1 #include<iostream>
  2 #include<vector>
  3 #include<stack>
  4 const int MAXN=5000+10;
  5 using namespace std;
  6 vector<int>mp1[MAXN];//原图
  7 vector<int>mp2[MAXN];//反向图
  8 stack<int>S;
  9 bool mark[MAXN];//标记元素是否在栈中
 10 int color[MAXN];//缩点,染色
 11 int to[MAXN];//入度
 12 int n,m,cnt,_count;
 13 int dfn[MAXN],low[MAXN];
 14 int num[MAXN];//用来保存所有的最大点
 15 int dp[MAXN];//用于保存每个强连通分量的点数
 16 
 17 //求强连通分量Tarjan算法
 18 void Tarjan(int u){
 19     dfn[u]=low[u]=++cnt;
 20     mark[u]=true;
 21     S.push(u);
 22     for(int i=0;i<mp1[u].size();i++){
 23         int v=mp1[u][i];
 24         if(dfn[v]==0){
 25             Tarjan(v);
 26             low[u]=min(low[u],low[v]);
 27         }else if(mark[v]){
 28             low[u]=min(low[u],dfn[v]);
 29         }
 30     }
 31     if(low[u]==dfn[u]){
 32         int v;
 33         do{
 34             v=S.top();
 35             S.pop();
 36             mark[v]=false;
 37             color[v]=_count;//缩点,染色
 38             dp[_count]++;//保存该强联通分量的点数
 39         }while(u!=v);
 40         _count++;
 41     }
 42 }
 43 
 44 //计算反向图中每一个入度为0的点的最大值
 45 int dfs(int u){
 46     mark[u]=true;
 47     cnt+=dp[u];
 48     for(int i=0;i<mp2[u].size();i++){
 49         int v=mp2[u][i];
 50         if(!mark[v])dfs(v);
 51     }
 52     return cnt;
 53 }
 54 
 55 int main(){
 56     int _case,t=1;
 57     scanf("%d",&_case);
 58     while(_case--){
 59         scanf("%d%d",&n,&m);
 60         for(int i=0;i<n;i++){
 61             mp1[i].clear();
 62             mp2[i].clear();
 63         }
 64         for(int i=1;i<=m;i++){
 65             int x,y;
 66             scanf("%d%d",&x,&y);
 67             mp1[x].push_back(y);
 68         }
 69         memset(mark,false,sizeof(mark));
 70         memset(dfn,0,sizeof(dfn));
 71         memset(low,0,sizeof(low));
 72         memset(color,0,sizeof(color));
 73         memset(dp,0,sizeof(dp));
 74         memset(to,0,sizeof(to));
 75         memset(num,0,sizeof(num));
 76         _count=0,cnt=0;
 77         for(int i=0;i<n;i++){
 78             if(dfn[i]==0){
 79                 Tarjan(i);
 80             }
 81         }
 82         //重新构图,建反向图
 83         for(int i=0;i<n;i++){
 84             for(int j=0;j<mp1[i].size();j++){
 85                 //不在同一个连通分量的点
 86                 if(color[i]!=color[mp1[i][j]]){
 87                     mp2[color[mp1[i][j]]].push_back(color[i]);
 88                     to[color[i]]++;//入度
 89                 }
 90             }
 91         }
 92         printf("Case %d: ",t++);
 93         int MAX=-1,tag=0;
 94         for(int i=0;i<_count;i++){
 95             //最大值一定在反向图中入度为0的点中
 96             cnt=0;
 97             if(to[i]==0){
 98                 memset(mark,false,sizeof(mark));
 99                 int cnt=dfs(i);
100                 num[i]=cnt;//保存每一个入度0的最大值
101                 MAX=max(MAX,cnt);
102             }
103         }
104         printf("%d\n",MAX-1);
105         //在原图中找最大的点
106         for(int i=0;i<n;i++){
107             if(num[color[i]]==MAX){
108                 if(!tag){
109                     printf("%d",i);
110                     tag=1;
111                 }else{
112                     printf(" %d",i);
113                 }
114             }
115         }
116         printf("\n");
117     }
118     return 0;
119 }

 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3072

思路:先缩点变成有向无环图,dp[i][j]表示缩点后的第i个连通分量到第j个连通分量的最小花费(环内花费为0),从而求每个点的最小入边就行了。

View Code
 1 #include<iostream>
 2 #include<vector>
 3 #include<stack>
 4 const int MAXN=100000+10;
 5 const int N=400;
 6 const int inf=1<<30;
 7 using namespace std;
 8 
 9 vector<int>mp[MAXN];
10 stack<int>S;
11 int n,m,_count,cnt;
12 bool mark[MAXN];
13 int dfn[MAXN],low[MAXN];
14 int color[MAXN];//缩点,染色
15 int dp[N][N];
16 struct Node{
17     int x,y,cost;
18 }node[MAXN];
19 
20 //Tarjan算法求强连通分量
21 void Tarjan(int u){
22     dfn[u]=low[u]=++cnt;
23     mark[u]=true;
24     S.push(u);
25     for(int i=0;i<mp[u].size();i++){
26         int v=mp[u][i];
27         if(dfn[v]==0){
28             Tarjan(v);
29             low[u]=min(low[u],low[v]);
30         }else if(mark[v]){
31             low[u]=min(low[u],dfn[v]);
32         }
33     }
34     if(low[u]==dfn[u]){
35         int v;
36         do{
37             v=S.top();
38             S.pop();
39             mark[v]=false;
40             color[v]=_count;//染色
41         }while(u!=v);
42         _count++;
43     }
44 }
45 
46 
47 int main(){
48     while(~scanf("%d%d",&n,&m)){
49         for(int i=0;i<n;i++)mp[i].clear();
50         for(int i=0;i<m;i++){
51             scanf("%d%d%d",&node[i].x,&node[i].y,&node[i].cost);
52             mp[node[i].x].push_back(node[i].y);
53         }
54         memset(mark,false,sizeof(mark));
55         memset(dfn,0,sizeof(dfn));
56         memset(low,0,sizeof(low));
57         memset(color,0,sizeof(color));
58         _count=0,cnt=0;
59         for(int i=0;i<n;i++){
60             if(dfn[i]==0){
61                 Tarjan(i);
62             }
63         }
64         for(int i=0;i<_count;i++){
65             for(int j=0;j<_count;j++){
66                 dp[i][j]=inf;
67             }
68         }
69         for(int i=0;i<m;i++){
70             if(color[node[i].x]!=color[node[i].y]){
71                 dp[color[node[i].x]][color[node[i].y]]=min(
72                     dp[color[node[i].x]][color[node[i].y]],
73                     node[i].cost);
74             }
75         }
76         memset(mark,false,sizeof(mark));
77         int ans=0;
78         //选择每个点的最小入边
79         for(int i=0;i<_count;i++){
80             int tmp=inf,l=0;
81             for(int j=0;j<_count;j++){
82                 for(int k=0;k<_count;k++){
83                     if(!mark[k]&&tmp>dp[j][k]){
84                         tmp=dp[j][k];
85                         l=k;
86                     }
87                 }
88             }
89             if(tmp==inf)break;
90             ans+=tmp;
91             mark[l]=true;
92         }
93         printf("%d\n",ans);
94     }
95     return 0;
96 }

 

 

posted @ 2013-04-10 20:46  ihge2k  阅读(701)  评论(0编辑  收藏  举报