题目描述

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

  \(n\leq 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\n");
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\n",ans);
// for(auto v:a)
// printf("%d %d\n",v.first,v.second);
for(i=1;i<=len;i++)
printf("%d %d\n",ax[i],ay[i]);
return 0;
}

【XSY1762】染色问题 网络流的更多相关文章

  1. 刷题总结——奇怪的游戏(scoi2012)

    题目: 题目描述 Blinker 最近喜欢上一个奇怪的游戏.这个游戏在一个 N*M  的棋盘上玩,每个格子有一个数.每次 Blinker  会选择两个相邻的格子,并使这两个数都加上 1.现在 Blin ...

  2. P3756 [CQOI2017]老C的方块

    题目链接 看到网格图+最优化问题,当然要想黑白染色搞网络流.不过这道题显然无法用黑白染色搞定. 仔细观察那四种图形,发现都是蓝线两边一定有两个格子,两个格子旁边一定还有且仅有一个格子.因此我们可以这么 ...

  3. CSP-S 2021 爆零记

    前言 本人今年高二蒟蒻OIer,高一刚刚接触OI. 感觉可能要直接退役了555~ 希望还有机会靠NOIP翻盘 Day - 暑假 为了备战CSP提前返校,与xzh一起划水,总之刷了不少题,我也大受震撼 ...

  4. 【线性规划与网络流 24题】已完成(3道题因为某些奇怪的原因被抛弃了QAQ)

    写在前面:SDOI2016 Round1滚粗后蒟蒻开始做网络流来自我拯救(2016-04-11再过几天就要考先修课,现在做网络流24题貌似没什么用←退役节奏) 做的题目将附上日期,见证我龟速刷题. 1 ...

  5. BZOJ-2756 奇怪的游戏 黑白染色+最大流+当前弧优化+二分判断+分类讨论

    这个题的数据,太卡了,TLE了两晚上,各种调试优化,各种蛋疼. 2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec Memory Limit: 128 MB Submit ...

  6. 网络流系列算法总结(bzoj 3438 1061)

    网络流嘛,怎么看都是一堆逗逼题嘛,反正遇到还是都做不起嘛.... 网络流的模板非常简单,难点都在于建图,网络流的建图解决问题范围之广,下至A+B Problem,上至单纯形,线性规划.所以如果对于网络 ...

  7. 【HDU4859】 海岸线(网络流-最小割)

    Problem Description 欢迎来到珠海! 由于土地资源越来越紧张,使得许多海滨城市都只能依靠填海来扩展市区以求发展.作为Z市的决策人,在仔细观察了Z市地图之后,你准备通过填充某些海域来扩 ...

  8. 「CODVES 1922 」骑士共存问题(二分图的最大独立集|网络流)&dinic

    首先是题目链接  http://codevs.cn/problem/1922/ 结果发现题目没图(心情复杂 然后去网上扒了一张图 大概就是这样了. 如果把每个点和它可以攻击的点连一条边,那问题就变成了 ...

  9. 洛谷P4003 无限之环(infinityloop)(网络流,费用流)

    洛谷题目传送门 题目 题目描述 曾经有一款流行的游戏,叫做 Infinity Loop,先来简单的介绍一下这个游戏: 游戏在一个 n ∗ m 的网格状棋盘上进行,其中有些小方格中会有水管,水管可能在格 ...

随机推荐

  1. RuntimeError: Model class apps.users.models.User doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.

    报错代码: File "/home/bsodgm/Desktop/Django_projection/mall/apps/users/views.py", line 9, in & ...

  2. RPM包制作过程(一)

    本机环境:centos7,64位 1. 首先安装工具,rpmbuild可能在rpmdevtools里已经包含 #yum install rpm-devel.x86_64 #yum install rp ...

  3. hibernate延迟加载org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.javakc.hibernate.onetomany.entity.DeptEntity.emp, could not initialize proxy - no Session

    public static void main(String[] args) {  DeptEntity dept = getDept("402882e762ae888d0162ae888e ...

  4. Mike and strings CodeForces - 798B (简洁写法)

    题目链接 时间复杂度 O(n*n*|s| ) 纯暴力,通过string.substr()函数来构造每一个字符串平移后的字符串. #include <iostream> #include & ...

  5. Python里面如何拷贝一个对象

    1.赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个. In [168]: a Out[168]: [1, 2, 3] In [169]: b=a In [170]: a ...

  6. 通过C#调用,实现js加密代码的反混淆,并运行js函数

    前一篇我测试了vba调用htmlfile做反混淆,并执行js加密函数的代码.本文换成C#实现. 联系QQ:564955427 C#操作JS函数,可以通过ScriptControl组件,但这个组件只能在 ...

  7. 堆排、python实现堆排

    一.堆-完全二叉树 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),是不稳定排序 堆排序中的堆有大顶堆.小顶堆两种.他们都是完 ...

  8. Elasticsearch 5.0Head插件

    Elasticsearch 5.0 —— Head插件部署指南   使用ES的基本都会使用过head,但是版本升级到5.0后,head插件就不好使了.下面就看看如何在5.0中启动Head插件吧! 官方 ...

  9. IdentityServer4【QuickStart】之设置和概述

    设置和概述 有两个基本的方式来开启一个新的IdentityServer项目: 从头开始 从asp.net Identity模板开始 如果你从头开始,我们提供了一些基于内存中构建的存储,所以你不必一开始 ...

  10. org.elasticsearch.client.transport.NoNodeAvailableException

    SpringBoot连接elasticsearch异常 2018-09-11 16:03:43.692 ERROR 8684 --- [ main] o.s.boot.SpringApplicatio ...