hdu 3681The King’s Problem(强连通分量+最小路径覆盖)
2015-07-26 14:12
288 查看
//hdu 3861 //给定一张有向图,划分成几个部分, //对于u可以到v,v可以到u的点必须在同一部分 //同一部分中u可以到v或者v可以到u //我们首先将图的强连通分量写出来,缩点, //对于当前的有向无环图求最小路径覆盖 //为什么是最小路径覆盖呢? //因为每一个部分的任两个点都是单向可达的,实际上每一部分都是一个路径, //因为若分叉,由于方向性,必然分叉与分叉直接互不可达,不符合要求。 //在这里我用了比较复杂的二分图匹配算法,可以用匈牙利算法。 #include<cstdio> #include<cstring> #include<algorithm> const int N=5010,M=100100; const int INF=1<<28; using namespace std; struct Edge{ int from,to,next; }edge[M],edge2[M]; int cnt,cnt2; int head ,head2 ; void addedge(int u,int v){ edge[cnt].from=u;edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++; } void addedge2(int u,int v){ edge2[cnt2].from=u;edge2[cnt2].to=v;edge2[cnt2].next=head2[u];head2[u]=cnt2++; } struct Tarjan{ int dfn ,low ; int index,col; int flag ; int Stack ,inst ; int top; void init(){ index=0;col=0;top=0; memset(dfn,0,sizeof(dfn)); memset(inst, 0, sizeof(inst)); } void tarjan(int u){ dfn[u]=low[u]=++index; Stack[top++]=u;inst[u]=1; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(inst[v]){ low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]){ int k; ++col; do{ k=Stack[--top]; inst[k]=0; flag[k]=col; }while(k!=u); } } void build(int n){ for(int i=1;i<=n;i++){ for(int j=head[i];j!=-1;j=edge[j].next){ int u=i,v=edge[j].to; if(flag[u]!=flag[v]){ addedge2(flag[u],flag[v]); } } } } }tj; struct HK{//用HK算法求解二分最大匹配问题(时间复杂度为sqrt(v)*e) int nx,ny,dis; int cx ;//cx[i]表示左集合i顶点所匹配的右集合的顶点序号 int cy ; //cy[i]表示右集合i顶点所匹配的左集合的顶点序号 int dx ; int dy ; int Q ; bool bmask ; bool searchpath(){//极大最短增广路集 int front,rear; front=rear=0;//初始化队列 dis=INF; memset(dx, -1, sizeof(dx)); memset(dy, -1, sizeof(dy)); for(int i=1;i<=nx;i++){ if(cx[i]==-1)//左边未匹配 { Q[rear++]=i;//将左边节点放入队列 dx[i]=0;//分层 所有潜在起点构成0层 } } while(front<rear){ int u=Q[front++];//u都是未匹配的 if(dx[u]>dis)break; for(int i=head2[u];i!=-1;i=edge2[i].next){ int v=edge2[i].to; if(dy[v]==-1){//相邻未分层构成i+1层。 dy[v]=dx[u]+1;//v对应的距离 为u对应距离加1 if(cy[v]==-1)dis=dy[v];//右侧未匹配,更新最短距离 else{ dx[cy[v]]=dy[v]+1;//右侧已经匹配,根据已匹配边回溯。分层 Q[rear++]=cy[v];//左侧已匹配点入队。 } } } } return dis!=INF; } int findpath(int u){//只搜索极大最短增广路集中的边 for(int i=head2[u];i!=-1;i=edge2[i].next){ int v=edge2[i].to; if(!bmask[v]&&dy[v]==dx[u]+1){//反向搜索的过程 bmask[v]=1; if(cy[v]!=-1&&dy[v]==dis)continue; if(cy[v]==-1||findpath(cy[v])){ cy[v]=u; cx[u]=v; return 1; } } } return 0; } int Max_match(){ int res=0; memset(cx,-1,sizeof(cx)); memset(cy,-1,sizeof(cy)); while(searchpath()){ memset(bmask, 0, sizeof(bmask)); for(int i=1;i<=nx;i++){ if(cx[i]==-1){ res+=findpath(i); } } } return res; } }; HK hk; void init(){ cnt=cnt2=0; memset(head,-1,sizeof(head)); memset(head2, -1, sizeof(head2)); } int main(){ int T; scanf("%d",&T); while(T--){ int n,m; scanf("%d%d",&n,&m); init(); for(int i=0;i<m;i++){ int u,v; scanf("%d%d",&u,&v); addedge(u,v); } tj.init(); for(int i=1;i<=n;i++){ if(!tj.dfn[i])tj.tarjan(i); } tj.build(n); hk.nx=hk.ny=tj.col; printf("%d\n",tj.col-hk.Max_match()); } return 0; }
相关文章推荐
- Project Euler:Problem 92 Square digit chains
- 获取网络连接名称“本地连接”的两种方法
- DNS基本原理与配置
- Unicode字符列表(超完整)
- 最简单的汇编程序
- View事件传递 touch事件分发
- Server Tomcat v7.0 Server at localhost failed to start
- Javascript Ajax技术运用
- iOS中几种数据持久化方案:我要永远地记住你!
- 最短路默写
- poj 3259 Wormholes(Bellman-Ford)
- 树
- Apache不记录指定文件类型
- ios coredata的用法和利弊
- httpClient模拟登陆校内某系统
- GridView+DiskLruCache+LruCache+ViewPage显示图片效果
- 内存分配(堆、栈、BSS、代码段、数据段) --分析
- [转]STRUTS2中的OGNL
- Nginx DHCP TFTP Kickstart搭建自动安装系统
- [LeetCOde][Java] Best Time to Buy and Sell Stock III