您的位置:首页 > 其它

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

2014-05-26 17:55 507 查看
题目链接: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

;
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 }


 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: