• 【XSY1762】染色问题 网络流


    题目描述

      给定一张(n)个点(m)条边的无向图。每个顶点有一个颜色,要么是黑,要么是白。我们想进行一些操作,使得最终每一条边的两个端点都是不同的颜色。每一次操作,你可以将一条边的两个端点交换颜色。求最少的操作次数和具体的操作方式。

      (nleq 500)

    题解

      首先黑白染色,假设要让染出来的黑点最终成为黑点,那么

       1.对于原来的每个黑点(i),连边((S,i,1,0))

       2.对于染出来的每个黑点(i),连边((i,T,1,0))

       3.对于原图中的每条边((u,v)),连边((u,v,infty,1),(v,u,infty,1)),表示交换两个端点的花费。

      跑完费用流后,每次bfs找到一条从(S)(T)的路径,通过某些方法交换第一个点和最后一个点。

      对于一条长度大于(1)的路径,第一个点一定是白色的,最后一个点一定是黑色的。(第一个点靠(T),最后一个点靠(S)

      

      先把这个序列切成很多段,每段只有最右边的点是黑色的。

      

      把每段的黑点调到最前面

      

      再从后往前交换每段的第一个点和前一段的最后一个点。

      

      这样可以用长度(-1)步内交换第一个点和最后一个点。

      时间复杂度:(O(???))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    #include<queue>
    #include<list>
    #include<vector>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    queue<int> q;
    //vector<pii> a;
    int ax[1000010];
    int ay[1000010];
    int len=0;
    struct li
    {
    	int h[510];
    	int v[100010];
    	int t[100010];
    	int n;
    	li()
    	{
    		memset(h,0,sizeof h);
    		n=0;
    	}
    	void add(int x,int y)
    	{
    		n++;
    		v[n]=y;
    		t[n]=h[x];
    		h[x]=n;
    	}
    };
    li l;
    struct graph
    {
    	int h[510];
    	int u[500010];
    	int v[500010];
    	int w[500010];
    	int c[500010];
    	int t[500010];
    	int p[500010];
    	int n;
    	void clear()
    	{
    		n=0;
    		memset(h,0,sizeof h);
    	}
    	void add(int x,int y,int z,int d)
    	{
    		n++;
    		u[n]=x;
    		v[n]=y;
    		w[n]=d;
    		c[n]=z;
    		p[n]=0;
    		t[n]=h[x];
    		h[x]=n;
    	}
    	int S,T;
    	int gd[510];
    	int gb[510];
    	int gf[510];
    	int flow,cost;
    	int f[510];
    	int op(int x)
    	{
    		return ((x-1)^1)+1;
    	}
    	int spfa()
    	{
    		memset(gd,0x7f,sizeof gd);
    		gd[S]=0;
    		gf[S]=0;
    		q.push(S);
    		int i,x;
    		while(!q.empty())
    		{
    			x=q.front();
    			q.pop();
    			gb[x]=0;
    			if(gd[x]>=gd[T])
    				continue;
    			for(i=h[x];i;i=t[i])
    				if(c[i]&&gd[v[i]]>gd[x]+w[i])
    				{
    					gd[v[i]]=gd[x]+w[i];
    					gf[v[i]]=i;
    					if(!gb[v[i]])
    					{
    						gb[v[i]]=1;
    						q.push(v[i]);
    					}
    				}
    		}
    		if(gd[T]==0x7f7f7f7f)
    			return 0;
    		flow++;
    		cost+=gd[T];
    		for(i=gf[T];i;i=gf[u[i]])
    		{
    			c[i]--;
    			p[i]++;
    			c[op(i)]++;
    			p[op(i)]--;
    		}
    		return 1;
    	}
    	int maxflow()
    	{
    		flow=cost=0;
    		while(spfa());
    		return cost;
    	}
    	int p1[500010];
    	int p2[500010];
    	void check()
    	{
    		memset(gb,0,sizeof gb);
    		gb[S]=1;
    		gf[S]=0;
    		q.push(S);
    		int i;
    		while(!q.empty())
    		{
    			int x=q.front();
    			q.pop();
    			for(i=h[x];i;i=t[i])
    				if(p[i]&&!gb[v[i]])
    				{
    					gb[v[i]]=1;
    					gf[v[i]]=i;
    					if(v[i]==T)
    					{
    						while(!q.empty())
    							q.pop();
    						return;
    					}
    					q.push(v[i]);
    				}
    		}
    	}
    	void getans()
    	{
    		check();
    		int i;
    		int t1=0,t2=0;
    		for(i=gf[T];i;i=gf[u[i]])
    		{
    			if(v[i]!=T)
    				p1[++t1]=v[i];
    			p[i]--;
    		}
    		for(i=t1;i>=2;i--)
    			if(f[p1[i-1]])
    				p2[++t2]=i;
    			else
    			{
    //				a.push_back(pii(p1[i-1],p1[i]));
    				ax[++len]=p1[i-1];
    				ay[len]=p1[i];
    				swap(f[p1[i]],f[p1[i-1]]);
    			}
    		for(i=t2;i>=1;i--)
    		{
    //			a.push_back(pii(p1[p2[i]],p1[p2[i]-1]));
    			ax[++len]=p1[p2[i]];
    			ay[len]=p1[p2[i]-1];
    			swap(f[p1[p2[i]]],f[p1[p2[i]-1]]);
    		}
    	}
    };
    graph g1,g2;
    char s[510];
    int c[510];
    int from[510][510];
    int d[510][510];
    int vis[100010];
    int s1,s2;
    int b,w;
    int ans;
    list<int> e,e1,e2;
    void failed()
    {
    	printf("-1
    ");
    	exit(0);
    }
    void dfs(int x,int p)
    {
    	if(~vis[x])
    	{
    		if(vis[x]!=p)
    			failed();
    		return;
    	}
    	e.push_back(x);
    	vis[x]=p;
    	if(c[x])
    		b++;
    	else
    		w++;
    	if(p)
    	{
    		s1++;
    		e1.push_back(x);
    	}
    	else
    	{
    		s2++;
    		e2.push_back(x);
    	}
    	int i;
    	for(i=l.h[x];i;i=l.t[i])
    		dfs(l.v[i],p^1);
    }
    int build1()
    {
    	for(auto v1:e)
    	{
    		int i;
    		for(i=l.h[v1];i;i=l.t[i])
    		{
    			int v2=l.v[i];
    			g1.add(v1,v2,1000,1);
    			g1.add(v2,v1,0,-1);
    			g1.add(v2,v1,1000,1);
    			g1.add(v1,v2,0,-1);
    		}
    		if(c[v1])
    		{
    			g1.add(g1.S,v1,1,0);
    			g1.add(v1,g1.S,0,0);
    		}
    	}
    	for(auto v1:e2)
    	{
    		g1.add(v1,g1.T,1,0);
    		g1.add(g1.T,v1,0,0);
    	}
    	return g1.maxflow();
    }
    int build2()
    {
    	for(auto v1:e)
    	{
    		int i;
    		for(i=l.h[v1];i;i=l.t[i])
    		{
    			int v2=l.v[i];
    			g2.add(v1,v2,1000,1);
    			g2.add(v2,v1,0,-1);
    			g2.add(v2,v1,1000,1);
    			g2.add(v1,v2,0,-1);
    		}
    		if(c[v1])
    		{
    			g2.add(g2.S,v1,1,0);
    			g2.add(v1,g2.S,0,0);
    		}
    	}
    	for(auto v1:e1)
    	{
    		g2.add(v1,g2.T,1,0);
    		g2.add(g2.T,v1,0,0);
    	}
    	return g2.maxflow();
    }
    void rd(int &s)
    {
    	int c;
    	while((c=getchar())<'0'||c>'9');
    	s=c-'0';
    	while((c=getchar())>='0'&&c<='9')
    		s=s*10+c-'0';
    }
    int main()
    {
    	int n,m;
    //	scanf("%d%d",&n,&m);
    	rd(n);
    	rd(m);
    	int i;
    	scanf("%s",s+1);
    	for(i=1;i<=n;i++)
    		c[i]=s[i]-'0';
    	int x,y;
    	for(i=1;i<=m;i++)
    	{
    //		scanf("%d%d",&x,&y);
    		rd(x);
    		rd(y);
    		l.add(x,y);
    		l.add(y,x);
    	}
    	memset(vis,-1,sizeof vis);
    	ans=0;
    	g1.S=g2.S=n+1;
    	g1.T=g2.T=n+2;
    	for(i=1;i<=n;i++)
    		if(vis[i]==-1)
    		{
    			w=b=s1=s2=0;
    			e.clear();
    			e1.clear();
    			e2.clear();
    			dfs(i,0);
    			if(w!=s1&&w!=s2)
    				failed();
    			int ans1=0x7fffffff,ans2=0x7fffffff;
    			g1.clear();
    			g2.clear();
    			int f1,f2;
    			if(w==s1&&b==s2)
    			{
    				ans1=build1();
    				f1=g1.flow;
    			}
    			if(b==s1&&w==s2)
    			{
    				ans2=build2();
    				f2=g2.flow;
    			}
    			if(ans1<ans2)
    			{
    				ans+=ans1;
    				memcpy(g1.f,c,sizeof c);
    				while(f1--)
    					g1.getans();
    			}
    			else
    			{
    				ans+=ans2;
    				memcpy(g2.f,c,sizeof c);
    				while(f2--)
    					g2.getans();
    			}
    		}
    	printf("%d
    ",ans);
    //	for(auto v:a)
    //		printf("%d %d
    ",v.first,v.second);
    	for(i=1;i<=len;i++)
    		printf("%d %d
    ",ax[i],ay[i]);
    	return 0;
    }
    
  • 相关阅读:
    为什么obj不等于obj?
    前端基础:深入理解内存空间
    微信小程序之富文本解析
    微信小程序加载更多 点击查看更多
    目前为止最全的微信小程序项目实例
    小程序图文列表一行俩列
    关于小程序 scroll-view 左右横向滑动没有效果(无法滑动)问题
    微信小程序商品筛选,侧方弹出动画选择页面
    小程序-带参跳转页面
    css-background-image 背景图片太大或太小
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8511233.html
Copyright © 2020-2023  润新知