zoukankan      html  css  js  c++  java
  • hdu3861 The King’s Problem 强连通缩点+DAG最小路径覆盖

      对多校赛的题目,我深感无力。题目看不懂,英语是能懂的,题目具体的要求以及需要怎么做没有头绪。样例怎么来的都不明白。好吧,看题解吧。

      http://www.cnblogs.com/kane0526/archive/2013/07/21/3203992.html

    题目大意:

      把一幅有向图中的点最少可以划分为几个区域。划分的规则是:1、可以互相到达的点必须在同一区域。2、每个城市都必须被划分。3、对于属于同一区域中的任意两点,要么满足u->v,要么满足v->u。

      第三条规则需要着重解释一下。对于测试数据1->2,1->3,因为2与3之间没有边,所以2与3必须被划为2个区域。所以答案是2。

    做法:

      建图求强连通(Tarjan算法),然后对得到的DAG,重新建图。遍历每条边,不属于同一连通分支的点就连一条边。正向图和反向图都可以。

      最后答案就是SCC - ans。SCC 是连通分支数,ans是最大匹配数。因为这里求的最小路径覆盖。

      最小路径覆盖 =  顶点数 -  最大匹配数

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<vector>
      5 #include<queue>
      6 #include<algorithm>
      7 using namespace std;
      8 const int N =5010, M=100010,INF=0x3f3f3f3f;;
      9 struct node
     10 {
     11     int to, next;
     12 }edge[M];
     13 int head[N], low[N], dfn[N], sta[N], belg[N], num[N];
     14 bool vis[N];
     15 int scc,index,top, tot;
     16 void tarbfs(int u)
     17 {
     18     int i,j,k,v;
     19     low[u]=dfn[u]=++index;
     20     sta[top++]=u;
     21     vis[u]=1;
     22     for(i=head[u];i!=-1;i=edge[i].next)
     23     {
     24         v=edge[i].to;
     25         if(!dfn[v])
     26         {
     27             tarbfs(v);
     28             if(low[u]>low[v]) low[u]=low[v];
     29         }
     30         else if(vis[v]&&low[u]>dfn[v]) low[u]=dfn[v];
     31     }
     32     if(dfn[u]==low[u])
     33     {
     34         scc++;
     35         do
     36         {
     37             v=sta[--top];
     38             vis[v]=0;
     39             belg[v]=scc;
     40             num[scc]++;
     41         }
     42         while(v!=u) ;
     43     }
     44 }
     45 void Tarjan(int n)
     46 {
     47     memset(vis,0,sizeof(vis));
     48     memset(dfn,0,sizeof(dfn));
     49     memset(num,0,sizeof(num));
     50     memset(low,0,sizeof(low));
     51     index=scc=top=0;
     52     for(int i=1;i<=n;i++)
     53         if(!dfn[i]) tarbfs(i);
     54 }
     55 void init()
     56 {
     57     tot=0;
     58     memset(head,-1,sizeof(head));
     59 }
     60 void addedge(int i,int j)
     61 {
     62     edge[tot].to=j; edge[tot].next=head[i];head[i]=tot++;
     63 }
     64 int cx[N],cy[N],dx[N],dy[N];
     65 bool bmask[N];
     66 int nx,dis,ans;
     67 vector<int> bmap[N];
     68 bool searchpath()
     69 {
     70     queue<int> q;
     71     dis=INF;
     72     memset(dx,-1,sizeof(dx));
     73     memset(dy,-1,sizeof(dy));
     74     for(int i=1;i<=nx;i++)
     75     {
     76         if(cx[i]==-1){ q.push(i); dx[i]=0; }
     77         while(!q.empty())
     78         {
     79             int u=q.front(); q.pop();
     80             if(dx[u]>dis) break;
     81             for(int i=0;i<bmap[u].size();i++)
     82             {
     83                 int v=bmap[u][i];
     84                 if(dy[v]==-1)
     85                 {
     86                     dy[v]= dx[u] + 1;
     87                     if(cy[v]==-1) dis=dy[v];
     88                     else
     89                     {
     90                         dx[cy[v]]= dy[v]+1;
     91                         q.push(cy[v]);
     92                     }
     93                 }
     94             }
     95         }
     96     }
     97     return dis!=INF;
     98 }
     99 int findpath(int u)
    100 {
    101     for(int i=0;i<bmap[u].size();i++)
    102     {
    103         int v=bmap[u][i];
    104         if(!bmask[v]&&dy[v]==dx[u]+1)
    105         {
    106             bmask[v]=1;
    107             if(cy[v]!=-1&&dy[v]==dis) continue;
    108             if(cy[v]==-1||findpath(cy[v]))
    109             {
    110                 cy[v]=u; cx[u]=v;
    111                 return 1;
    112             }
    113         }
    114     }
    115     return 0;
    116 }
    117 void maxmatch()
    118 {
    119     ans=0;
    120     memset(cx,-1,sizeof(cx));
    121     memset(cy,-1,sizeof(cy));
    122     while(searchpath())
    123     {
    124         memset(bmask,0,sizeof(bmask));
    125         for(int i=1;i<=nx;i++)
    126             if(cx[i]==-1) ans+=findpath(i);
    127     }
    128 }
    129 int main()
    130 {
    131     //freopen("test.txt","r",stdin);
    132     int cas,i,j,k,n,m;
    133     scanf("%d",&cas);
    134     while(cas--)
    135     {
    136         scanf("%d%d",&n,&m);
    137         init();
    138         while(m--)
    139         {
    140             scanf("%d%d",&i,&j);
    141             addedge(i,j);
    142         }
    143         Tarjan(n);
    144         for(i=1;i<=n;i++) bmap[i].clear();
    145         for(i=1;i<=n;i++)
    146         {
    147             for(k=head[i];k!=-1;k=edge[k].next)
    148             {
    149                 j=edge[k].to;
    150                 if(belg[i]!=belg[j]) bmap[belg[j]].push_back(belg[i]);
    151             }
    152         }
    153         nx=scc;
    154         maxmatch();
    155         printf("%d
    ",scc-ans);
    156     }
    157     return 0;
    158 }
    View Code
  • 相关阅读:
    telnet和ssh
    sersync实现实时同步
    rsync服务端一键安装rsync脚本(源码)
    rsync客户端一键安装rsync脚本(源码)
    rsync客户端一键安装rsync脚本(非源码)
    centos 建立Clamav自动扫描脚本
    DELL T110II Server如何通过RAID 级别迁移的方式在OMSA下实现磁盘阵列扩容?
    Dell PowerEdgeServerT110II USB Boot更新
    Centos7最小安装下Install Clamav(2017-06-09最后更新)
    Centos7 samba 匿名共享 简单config
  • 原文地址:https://www.cnblogs.com/Potato-lover/p/3989625.html
Copyright © 2011-2022 走看看