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
原文地址:https://www.cnblogs.com/Potato-lover/p/3989625.html