hdu 3861(缩点+最小路径覆盖)

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

思路:缩点是显然的:What’s more, for each pair of city (u, v), if there is one way to go from u to v and go from v to u, (u, v) have to belong to a same state.然后就是建新图了,求最大匹配即可。

这里有最小路径覆盖==|顶点个数|-最大匹配;

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 #include<stack>
 7 using namespace std;
 8 #define MAXN 5555
 9 vector<int>vet[MAXN];//原图
10 vector<int>map[MAXN];//缩点后的图
11 stack<int>S;
12 bool mark[MAXN];//标记元素是否在栈中
13 int color[MAXN];//缩点,染色
14 int n,m,cnt,_count;
15 int dfn[MAXN],low[MAXN];
16 int lx[MAXN],ly[MAXN];
17 bool visited[MAXN];
18 
19 //求有向图的强联通分量
20 void Tarjan(int u){
21    dfn[u]=low[u]=++cnt;
22    mark[u]=true;
23    S.push(u);
24    for(int i=0;i<vet[u].size();i++){
25       int v=vet[u][i];
26       //没访问过
27       if(dfn[v]==0){
28          Tarjan(v);
29          low[u]=min(low[u],low[v]);
30       }else if(mark[v]){ low[u]=min(low[u],dfn[v]); }
31    }
32    if(low[u]==dfn[u]){
33       int v;
34       do{
35          v=S.top();
36          S.pop();
37          mark[v]=false;
38          color[v]=_count;//缩点,染色
39       }while(u!=v);
40       _count++;
41    }
42 }
43 
44 
45 int dfs(int u){
46    for(int i=0;i<map[u].size();i++){
47       int v=map[u][i];
48       if(!visited[v]){
49          visited[v]=true;
50          if(ly[v]==-1||dfs(ly[v])){ ly[v]=u;lx[u]=v;return 1; }
51       }
52    }
53    return 0;
54 }
55 
56 
57 int MaxMatch(){
58    int res=0;
59    memset(lx,-1,sizeof(lx));
60    memset(ly,-1,sizeof(ly));
61    for(int i=0;i<_count;i++){
62       memset(visited,false,sizeof(visited));
63       if(lx[i]==-1)res+=dfs(i);
64    }
65    return res;
66 }
67 
68 int main(){
69    int _case,u,v;
70    scanf("%d",&_case);
71    while(_case--){
72       scanf("%d%d",&n,&m);
73       for(int i=1;i<=n;i++){ vet[i].clear();map[i].clear(); }
74       for(int i=1;i<=m;i++){
75          scanf("%d%d",&u,&v);
76          vet[u].push_back(v);
77       }
78       memset(mark,false,sizeof(mark));
79       memset(dfn,0,sizeof(dfn));
80       memset(low,0,sizeof(low));
81       memset(color,0,sizeof(color));
82       _count=cnt=0;
83       for(int i=1;i<=n;i++)if(dfn[i]==0)Tarjan(i);
84       for(int i=1;i<=n;i++){
85          for(int j=0;j<vet[i].size();j++){
86             if(color[i]!=color[vet[i][j]]){
87                map[color[i]].push_back(color[vet[i][j]]);
88             }
89          }
90       }
91       int ans=MaxMatch();
92       printf("%d\n",_count-ans);
93    }
94    return 0;
95 }
View Code

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值