• 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 }
  • 相关阅读:
    第5节 两牵引轴同步运动
    第4节 动一个牵引轴
    第3节 电控配置简介
    第2节 控制方案的制定
    第1节 中型PLC基本编程思路
    1200与VM(主动)之间的TCP/IP通讯
    西门子1200和温度计的模拟量应用
    西门子1200的高速计数功能和增量编码器功能
    西门子1200和V90之间(位置模式)的PID应用
    面试题68
  • 原文地址:https://www.cnblogs.com/wally/p/3012761.html
Copyright © 2020-2023  润新知