zoukankan      html  css  js  c++  java
  • [HAOI2017] 新型城市化

    给出的图中恰包含2个团,则图的补图为一个二分图,其最大独立集为原图的最大团。

    我们知道,二分图的最大独立集=V-最小顶点覆盖,最小顶点覆盖=最大匹配。

    问题转化为:计算删去后最大匹配减小的边集。

    所以建图跑最大流,对残余网络中的每一条满流边讨论。

    这需要用到tarjan:若该满流边的端点同属一个强连通,那么通过该边的增广路不是必须的,这条边就不能算在答案里。

    码吧。。 建图时要利用二分图染色。

    请务必启用-std=gnu++11开关

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    
    const int N=1e4+5;
    const int L=5e5+5;
    const int inf=0x3f3f3f3f;
    
    int S=N-1,T=N-2;
    int head[N],to[L],upp[L],last[L],cnt=1;
    int que[N],lev[N],hd,tl;
    
    inline void add_edge(int x,int y,int u1,int u2=0) {
    	to[++cnt]=y,upp[cnt]=u1,last[cnt]=head[x],head[x]=cnt;
    	to[++cnt]=x,upp[cnt]=u2,last[cnt]=head[y],head[y]=cnt; 
    }
    inline bool bfs() {
    	memset(lev,0,sizeof lev);
    	lev[S]=1;
    	que[hd=0,tl=1]=S;
    	while(hd<tl) {
    		int x=que[++hd];
    		for(int i=head[x]; i; i=last[i]) if(upp[i]>0 && !lev[to[i]]) 
    			lev[to[i]]=lev[x]+1, que[++tl]=to[i];
    	}
    	return lev[T]!=0;
    }
    int dfs(int x,int tf) {
    	if(x==T) return tf;
    	int tot=0,tmp;
    	for(int i=head[x]; i; i=last[i]) if(upp[i]>0 && lev[x]+1==lev[to[i]]) {
    		tmp=dfs(to[i],min(tf-tot,upp[i]));
    		if(tmp) upp[i]-=tmp,upp[i^1]+=tmp,tot+=tmp;
    		if(tot==tf) break;
    	}
    	if(!tot) lev[x]=-1;
    	return tot;
    }
    
    int n,m;
    vector<int> e[N];
    vector<pair<int,int>> ans;
    int col[N],low[N],dfn[N],idx;
    int sta[N],bel[N],tot,top;
    
    void ran(int x) {
    	for(int y: e[x]) if(!col[y]) 	
    		col[y]=3^col[x], ran(y);
    } 
    void pre(int x) {
    	dfn[x]=low[x]=++idx;
    	sta[++top]=x;
    	for(int i=head[x]; i; i=last[i]) if(upp[i]>0) {
    		if(!dfn[to[i]]) {
    			pre(to[i]);
    			low[x]=min(low[x],low[to[i]]);
    		} else if(!bel[to[i]]) 
    			low[x]=min(low[x],dfn[to[i]]);
    	}
    	if(dfn[x]==low[x]) {
    		tot++;
    		do bel[sta[top]]=tot; while(sta[top--]!=x);
    	}
    }
    
    
    int main() {
    	scanf("%d%d",&n,&m);
    	for(int x,y,i=m; i--; ) {
    		scanf("%d%d",&x,&y);
    		e[x].push_back(y);
    		e[y].push_back(x);
    	}
    	for(int i=1; i<=n; ++i) {
    		if(!col[i]) col[i]=1, ran(i);
    	}
    	for(int i=1; i<=n; ++i) {
    		if(col[i]==1) {
    			add_edge(S,i,1);
    			for(int j:e[i]) add_edge(i,j,1);
    		} else add_edge(i,T,1);
    	}
    	while(bfs()) dfs(S,inf);
    	for(int i=1; i<=n; ++i) {
    		if(!dfn[i]) pre(i);
    	}
    	if(!dfn[S]) pre(S);
    	if(!dfn[T]) pre(T);
    	for(int i=2; i<=cnt; i+=2) {
    		if(upp[i]==0 && bel[to[i]]!=bel[to[i^1]] 
    	&& to[i]!=S && to[i]!=T && to[i^1]!=S && to[i^1]!=T) 
    			ans.push_back(make_pair(to[i],to[i^1]));
    	}
    	for(pair<int,int> &p:ans) {
    		if(p.first>p.second) swap(p.first,p.second); 
    	}
    	sort(ans.begin(),ans.end());
    	printf("%llu
    ",ans.size());
    	for(pair<int,int> p:ans) {
    		printf("%d %d
    ",p.first,p.second);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    【百度地图API】如何快速创建带有标注的地图?——快速创建地图工具+如何标注商家
    【百度地图API】百度做了一个艰难的决定——取消密钥机制!!
    【设计师工具】3个好用的在线配色工具
    【百度地图API】建立全国银行位置查询系统(二)——怎样为地图添加控件
    【百度地图API】如何在地图上添加标注?——另有:坐标拾取工具+打车费用接口介绍
    【百度地图API】多家地图API文件大小对比
    “街坊”房产数字平台,昔日的思想,曾经的努力
    软件工程之感想
    .net执行性能,Winform性能优化?如何提高.net程序性能
    个人之思考整理
  • 原文地址:https://www.cnblogs.com/nosta/p/10167230.html
Copyright © 2011-2022 走看看