zoukankan      html  css  js  c++  java
  • P3731 [HAOI2017]新型城市化 网络流+TARJAN

    题意:

    戳这里

    分析:

    据说是典型题,我好菜还是不会

    题意转化一下,相当于每次找一条边,使得加上这条边之后,原图的最大团点数至少+1 , 乍一看没什么想法,但是题目又给出了一个条件,那就是保证原图最多可以被划分为两个最大团 ,又因为原图的最大团=补图的最大独立集=总点数-最小点覆盖数=总点数-补图最大匹配,所以我们要求的东西就转化为和补图最大匹配有关,而原图的补图就是一张二分图,所以我们要求的就是在这张二分图上,删掉哪条边会使得最大匹配至少减少 (1) ,即二分图的最大匹配必经边

    好像是一种经典题,没做过/kk

    具体做法就是,先跑一遍最大流,然后对于残量网络跑 (tarjan) ,枚举每一条满流的边,看一下它连接的两个点是不是在一个强连通分量里面

    感性理解一下就是,对于 (u o v) 这条边,如果 (u,v) 在一个(scc) 里面,那么残量网络里面,一定有一条或几条边可以代替这条满流的边,所以它不是必经边

    代码:

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define mk(x,y) make_pair(x,y)
    #define lc rt<<1
    #define rc rt<<1|1
    #define pb push_back
    #define fir first
    #define sec second
    
    using namespace std;
    
    namespace zzc
    {
    	inline int read()
    	{
    		int x=0,f=1;char ch=getchar();
    		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    		return x*f;
    	}
    	
    	const int maxn = 1e4+5;
    	const int maxm = 3e5+5;
    	const int inf = 0x3f3f3f;
    	int n,m,st,top,cnt=1,ed,idx,scc;
    	int head[maxn],dep[maxn],dfn[maxn],low[maxn],sta[maxn],col[maxn],bel[maxn];
    	bool vis[maxn];
    	vector<int> g[maxn];
    	vector<pii> ans;
    	queue<int> q;
    	struct edge
    	{
    		int to,nxt,w;
    	}e[maxm];
    	
    	void add(int u,int v,int w)
    	{
    		e[++cnt].to=v;
    		e[cnt].w=w;
    		e[cnt].nxt=head[u];
    		head[u]=cnt;
    	}
    	
    	void add_edge(int u,int v,int w)
    	{
    		add(u,v,w);add(v,u,0);
    	}
    	
    	void paint(int u,int c)
    	{
    		col[u]=c;
    		for(auto v:g[u]) if(!col[v]) paint(v,c*-1);
    	}
    	
    	bool bfs()
    	{
    		for(int i=st;i<=ed;i++) dep[i]=-1;
    		q.push(st);dep[st]=0;
    		while(!q.empty())
    		{
    			int u=q.front();q.pop();
    			for(int i=head[u];i;i=e[i].nxt)
    			{
    				int v=e[i].to;
    				if(e[i].w&&dep[v]==-1)
    				{
    					dep[v]=dep[u]+1;
    					q.push(v);
    				}
    			}
    		}
    		return dep[ed]!=-1;
    	}
    	
    	int dfs(int u,int flow)
    	{
    		if(u==ed) return flow;
    		int used=0,w;
    		for(int i=head[u];i;i=e[i].nxt)
    		{
    			int v=e[i].to;
    			if(e[i].w&&dep[v]==dep[u]+1)
    			{
    				w=dfs(v,min(e[i].w,flow-used));
    				e[i].w-=w;
    				e[i^1].w+=w;
    				used+=w;
    				if(used==flow) return used;
    			}
    		}
    		if(!used) dep[u]=-1;
    		return used;
    	}
    	
    	void dinic()
    	{
    		while(bfs()) dfs(st,inf);
    	}
    	
    	void tarjan(int u)
    	{
    		dfn[u]=low[u]=++idx;
    		sta[++top]=u;
    		vis[u]=true;
    		for(int i=head[u];i;i=e[i].nxt)
    		{
    			int v=e[i].to;
    			if(!e[i].w) continue;
    			if(!dfn[v])
    			{
    				tarjan(v);
    				low[u]=min(low[u],low[v]);
    			}
    			else if(vis[v]) low[u]=min(low[u],dfn[v]);
    		}
    		if(low[u]==dfn[u])
    		{
    			scc++;
    			do
    			{
    				vis[sta[top]]=false;
    				bel[sta[top]]=scc;
    			}
    			while(sta[top--]!=u);
    		}
    	}
    	
    	void work()
    	{
    		int a,b;
    		n=read();m=read();st=0;ed=n+1;
    		for(int i=1;i<=m;i++)
    		{
    			a=read();b=read();
    			g[a].pb(b);g[b].pb(a);
    		}
    		for(int i=1;i<=n;i++) if(!col[i]) paint(i,1);
    		for(int i=1;i<=n;i++)
    		{
    			if(col[i]==1)
    			{
    				add_edge(st,i,1);
    				for(auto v:g[i]) add_edge(i,v,1);
    			}
    			else add_edge(i,ed,1);
    		}
    		dinic();
    		for(int i=st;i<=ed;i++) if(!dfn[i]) tarjan(i);
    		for(int u=1;u<=n;u++)
    		{
    			if(col[u]==1)
    			{
    				for(int i=head[u];i;i=e[i].nxt)
    				{
    					int v=e[i].to;
    					if(col[v]==-1&&!e[i].w&&bel[u]!=bel[v]) ans.pb(u<v?mk(u,v):mk(v,u));
    				}
    			}
    		}
    		sort(ans.begin(),ans.end());
    		printf("%d
    ",(int)ans.size());
    		for(auto i:ans) printf("%d %d
    ",i.fir,i.sec);
    	}
    
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    死锁程序示例
    用Intellij打可执行jar包
    Semaphore tryAcquire release 正确的使用方法
    计算对象占用空间工具类
    mysql高效分页方案及原理
    乐视秒杀:每秒十万笔交易的数据架构解读
    mysql 联合索引(转)
    mysql中in和exists二者的区别和性能影响
    怎样避免 i f 判断过多,全复杂度较高,代码不美观的问题?
    Java中Enum类型的序列化(转)
  • 原文地址:https://www.cnblogs.com/youth518/p/14265323.html
Copyright © 2011-2022 走看看