zoukankan      html  css  js  c++  java
  • 洛谷 P3731 [HAOI2017]新型城市化【最大流(二分图匹配)+tarjan】

    我到底怎么建的图为啥要开这么大的数组啊?!
    神题神题,本来以为图论出不出什么花来了。
    首先要理解‘团’的概念,简单来说就是无向图的一个完全子图,相关概念详见度娘。
    所以关于团一般都是NP问题,只有二分图例外。而题目中有这样一句话“n座城市可以恰好被划分为不超过两个城市群”,并且给出的是没有的边,也就是这个图的补图,两个团就很显然表示这个补图是个二分图(我一开始还考虑1个团咋整后来发现根本不用整= =),模型就变成了二分图的最大独立集,考虑最大独立集=n-最大匹配,那么只要求出删掉哪些边会让最大匹配减少,也就是哪些边一定在最大匹配里即可。
    先看一下大概步骤:
    1.黑白染色,建出二分图(在这里用dinic求最大匹配因为懒得重建图这样tarjan直接按着满流边跑即可
    2.dinic
    3.顺着满流边用tarjan求scc
    4.把两端不在同一个强连通分量里、两端不是s或t、满流的边加进ans数组里,排个序输出
    为什么要这样做呢?
    首先没满流的边一定不在最大匹配里就不说了。
    然后对于两端能缩到一个scc里的边,一个点的一入一出都可能与它匹配,所以不一定在最大匹配里。

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1000005,inf=1e9;
    int n,m,h[N],cnt,c[N],s,t,le[N],dfn[N],low[N],tot,st[N],top,bl[N],con,co,x[N],y[N];
    bool v[N];
    struct qwe
    {
    	int ne,no,to,va;
    }e[N*20];
    struct qw
    {
    	int x,y;
    	qw(const int X=0,const int Y=0)
    	{
    		x=X,y=Y;
    		if(x>y)
    			swap(x,y);
    	}
    }ans[N];
    bool cmp(const qw &a,const qw &b)
    {
    	return a.x<b.x||(a.x==b.x&&a.y<b.y);
    }
    int read()
    {
    	int r=0,f=1;
    	char p=getchar();
    	while(p>'9'||p<'0')
    	{
    		if(p=='-')
    			f=-1;
    		p=getchar();
    	}
    	while(p>='0'&&p<='9')
    	{
    		r=r*10+p-48;
    		p=getchar();
    	}
    	return r*f;
    }
    void add(int u,int v,int w)
    {
    	cnt++;
    	e[cnt].ne=h[u];
    	e[cnt].no=u;
    	e[cnt].to=v;
    	e[cnt].va=w;
    	h[u]=cnt;
    }
    void ins(int u,int v,int w)
    {//cout<<u<<" "<<v<<endl;
    	add(u,v,w);
    	add(v,u,0);
    }
    void dfss(int u,int col)
    {
    	c[u]=col;
    	v[u]=1;
    	for(int i=h[u];i;i=e[i].ne)
    		if(!v[e[i].to])
    			dfss(e[i].to,col^1);
    }
    bool bfs()
    {
    	queue<int>q;
    	memset(le,0,sizeof(le));
    	le[s]=1;
    	q.push(s);
    	while(!q.empty())
    	{
    		int u=q.front();
    		q.pop();
    		for(int i=h[u];i;i=e[i].ne)
    			if(e[i].va>0&&!le[e[i].to])
    			{
    				le[e[i].to]=le[u]+1;
    				q.push(e[i].to);
    			}
    	}
    	return le[t];
    }
    int dfs(int u,int f)
    {//cout<<u<<" "<<f<<endl;
    	if(!f||u==t)
    		return f;
    	int us=0;
    	for(int i=h[u];i&&us<f;i=e[i].ne)
    		if(le[e[i].to]==le[u]+1&&e[i].va>0)
    		{
    			int t=dfs(e[i].to,min(e[i].va,f-us));
    			e[i].va-=t;
    			e[i^1].va+=t;
    			us+=t;
    		}
    	if(!us)
    		le[u]=0;
    	return us;
    }
    void dinic()
    {
    	while(bfs())
    		dfs(s,inf);
    }
    void tarjan(int u)
    {
    	dfn[u]=low[u]=++tot;
    	v[st[++top]=u]=1;
    	for(int i=h[u];i;i=e[i].ne)
    		if(!e[i].va)
    		{
    			if(!dfn[e[i].to])
    			{
    				tarjan(e[i].to);
    				low[u]=min(low[u],low[e[i].to]);
    			}
    			else if(v[e[i].to])
    				low[u]=min(low[u],dfn[e[i].to]);
    		}
    	if(dfn[u]==low[u])
    	{
    		con++;
    		while(st[top]!=u)
    		{
    			bl[st[top]]=con;
    			v[st[top--]]=0;
    		}
    		bl[st[top]]=con;
    		v[st[top--]]=0;
    	}
    }
    int main()
    {
    	n=read(),m=read();
    	for(int i=1;i<=m;i++)
    	{
    		x[i]=read(),y[i]=read();
    		add(x[i],y[i],0);add(y[i],x[i],1);
    	}
    	for(int i=1;i<=n;i++)
    		if(!v[i])
    			dfss(i,2);
    	memset(h,0,sizeof(h));
    	cnt=1;	
    	s=0,t=n+1;
    	for(int i=1;i<=n;i++)
    	{
    		if(c[i]==2)
    			ins(s,i,1);
    		else
    			ins(i,t,1);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		if(c[x[i]]==2)
    			ins(x[i],y[i],1);
    		else
    			ins(y[i],x[i],1);
    	}//cout<<"OKBUILD"<<endl;
    	dinic();//cout<<"OKDINIC"<<endl;
    	memset(v,0,sizeof(v));
    	for(int i=1;i<=n;i++)
    		if(!dfn[i])
    			tarjan(i);
    	for(int i=2;i<=cnt;i+=2)
    		if(!e[i].va&&bl[e[i].no]!=bl[e[i].to]&&e[i].no!=s&&e[i].no!=t&&e[i].to!=s&&e[i].to!=t)
    			ans[++co]=qw(e[i].no,e[i].to);
    	sort(ans+1,ans+1+co,cmp);
    	printf("%d
    ",co);
    	for(int i=1;i<=co;i++)
    		printf("%d %d
    ",ans[i].x,ans[i].y);
    	return 0;
    }
    
  • 相关阅读:
    【HDOJ】2267 How Many People Can Survive
    【HDOJ】2268 How To Use The Car
    【HDOJ】2266 How Many Equations Can You Find
    【POJ】2278 DNA Sequence
    【ZOJ】3430 Detect the Virus
    【HDOJ】2896 病毒侵袭
    求奇数的乘积
    平方和与立方和
    求数列的和
    水仙花数
  • 原文地址:https://www.cnblogs.com/lokiii/p/8524897.html
Copyright © 2011-2022 走看看