t个样例
n个点m条边
分成一些区
2个点互相能到达必须分在一个区
一个区中任何2个点可以u->v 或者v->u
任何点都要有自己的区
求最小的区的数目
强联通缩点
成新图
二分匹配 求最大匹配
最小路径覆盖=点数-最大匹配数
1 #include<stdio.h> 2 #include<algorithm> 3 #include<string.h> 4 #include<stack> 5 6 using namespace std; 7 8 #define MAXN 5010 9 #define MAXN1 100010 10 int head[MAXN],dfn[MAXN],low[MAXN],cou[MAXN],fa[MAXN]; 11 int cnt,k,num; 12 bool vis[MAXN],mark[MAXN]; 13 14 struct edg 15 { 16 int next,to,fr; 17 }x[MAXN1]; 18 void add(int u,int v) 19 { 20 x[cnt].next=head[u]; 21 x[cnt].fr=u; 22 x[cnt].to=v; 23 head[u]=cnt++; 24 } 25 stack<int>s; 26 27 void dfs(int u) 28 { 29 low[u]=dfn[u]=k++; 30 vis[u]=1; 31 s.push(u); 32 int i; 33 for(i=head[u];i!=-1;i=x[i].next) 34 { 35 int v=x[i].to; 36 if(!dfn[v]) 37 { 38 dfs(v); 39 low[u]=min(low[u],low[v]); 40 } 41 else if(vis[v]) 42 low[u]=min(low[u],dfn[v]); 43 } 44 if(dfn[u]==low[u]) 45 { 46 num++; 47 while(!s.empty()) 48 { 49 int now=s.top(); 50 s.pop(); 51 vis[now]=0; 52 fa[now]=num; 53 if(now==u)break; 54 } 55 } 56 } 57 int pa[MAXN]; 58 59 bool dfs1(int u) 60 { 61 int i; 62 for(i=head[u];i!=-1;i=x[i].next) 63 { 64 if(mark[x[i].to]) 65 continue; 66 mark[x[i].to]=1; 67 if(pa[x[i].to]==-1||dfs1(pa[x[i].to])) 68 { 69 pa[x[i].to]=u; 70 return 1; 71 } 72 } 73 return 0; //很重要 74 } 75 int main() 76 { 77 int t; 78 scanf("%d",&t); 79 80 while(t--) 81 { 82 int n,m,i; 83 scanf("%d%d",&n,&m); 84 cnt=0; 85 memset(head,-1,sizeof(head)); 86 memset(dfn,0,sizeof(dfn)); 87 memset(low,0,sizeof(low)); 88 89 for(i=1;i<=m;i++) 90 { 91 int a,b; 92 scanf("%d%d",&a,&b); 93 add(a,b); 94 } 95 k=1; 96 num=0; 97 for(i=1;i<=n;i++) //强联通 98 if(!dfn[i]) 99 dfs(i); 100 memset(head,-1,sizeof(head)); 101 memset(pa,-1,sizeof(pa)); 102 int en=cnt; 103 cnt=0; 104 for(i=0;i<en;i++) 105 { 106 int u,v; 107 u=fa[x[i].fr]; 108 v=fa[x[i].to]; 109 if(u!=v) 110 { 111 add(u,v); 112 } 113 } 114 int ans=0; 115 116 for(i=1;i<=num;i++) //二分匹配 117 { 118 memset(mark,0,sizeof(mark)); 119 if(dfs1(i)) 120 ans++; 121 } 122 printf("%d\n",num-ans); 123 } 124 125 return 0; 126 }
时间: 2024-10-06 16:47:53