- emm。一道模板题,本来想着30分钟写完,一点半赶紧开始打比赛……没想到,看题目理解题意花了20分钟,敲了10分钟。比赛完之后,写了30分钟吧,交上去果断0分。晚上调整思路之后,又写了一遍,仍然是0分。
- 在神犇帮助下,找到了自己的错误:用网络流跑最大匹配,建的边都是有向边!
Solution
- 题目给定
m对点对,这
m对点对互相之间没有连边。其他的点互相之间都有边,问:把哪个点对连通之后,最大团会变大。
- 在原图中是添加边使得最大团变大,对应在补图中当然就是割一条边,使得最大独立集变大。
- 最大独立集=点数-最大匹配数。那么就是割一条边使得最大匹配数变小。也就是求二分图关键边。
- 图中已经保证没有奇环,所以直接二分图染色。
- 建边跑最大流。
- tarjan求scc,判断关键边。
Coding
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e4+10;
const int M=4e6+10;
const int inf=1e9;
struct node{
int x,y,id1,id2;
}e[M],f[M];
int n,m,S,T,num,top,cnt,tot,flow,maxflow,lin[N],Next[M],ver[M],edge[M],dfn[N],low[N],ins[N],s[N],c[N],d[N],color[N];
int read(){
char ch=getchar();int num=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){num=(num<<1)+(num<<3)+(ch^48);ch=getchar();}
return num*f;
}
void dfs(int x,int col){
color[x]=col;
for(int i=lin[x];i;i=Next[i]){
int y=ver[i];
if(!color[y]) dfs(y,3-col);
}
}
void add(int x,int y){ver[++tot]=y;Next[tot]=lin[x];lin[x]=tot;}
void Add(int x,int y,int z){
ver[++tot]=y;Next[tot]=lin[x];lin[x]=tot;edge[tot]=z;
ver[++tot]=x;Next[tot]=lin[y];lin[y]=tot;edge[tot]=0;
}
bool bfs(){
queue<int>q;
memset(d,0,sizeof(d));
d[S]=1,q.push(S);
while(q.size()){
int x=q.front();q.pop();
for(int i=lin[x];i;i=Next[i]){
int y=ver[i];
if(!d[y]&&edge[i]){
d[y]=d[x]+1;q.push(y);
if(y==T) return 1;
}
}
}return 0;
}
int dinic(int x,int flow){
if(x==T) return flow;
int rest=flow;
for(int i=lin[x];i&&rest;i=Next[i]){
int y=ver[i];
if(d[y]==d[x]+1&&edge[i]){
int k=dinic(y,min(edge[i],rest));
if(!k) d[y]=0;
rest-=k,edge[i]-=k,edge[i^1]+=k;
if(!rest) return flow-rest;
}
}return flow-rest;
}
void tarjan(int x){
dfn[x]=low[x]=++num;ins[x]=1,s[++top]=x;
for(int i=lin[x];i;i=Next[i]){
int y=ver[i];
if(edge[i]&&!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}else if(ins[y]&&edge[i]) low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x]){
cnt++;int y;
do{
y=s[top--];c[y]=cnt;ins[y]=0;
}while(x!=y);
}
}
bool CMP(node a,node b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
int main(){
n=read(),m=read();
for(int i=1;i<=m;++i){
e[i].x=read(),e[i].y=read();
add(e[i].x,e[i].y);add(e[i].y,e[i].x);
}
for(int i=1;i<=n;++i) if(!color[i]) dfs(i,1);
S=0,T=n+1;tot=1;
memset(ver,0,sizeof(ver));
memset(lin,0,sizeof(lin));
memset(Next,0,sizeof(Next));
for(int i=1;i<=m;++i){
int x=e[i].x,y=e[i].y;
if(color[x]==2)Add(y,x,1);
else Add(x,y,1);
}
for(int i=1;i<=n;++i){
if(color[i]==1) Add(S,i,1);
else if(color[i]==2) Add(i,T,1);
}
while(bfs()){
while(flow=dinic(S,inf)) maxflow+=flow;
}
for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
int ans=0;
for(int i=2;i<=tot;i+=2){
int x=ver[i^1],y=ver[i];
if(x==0||y==0||x==T||y==T)continue;
if(edge[i]==0&&c[x]!=c[y])f[++ans].x=min(x,y),f[ans].y=max(x,y);
}
printf("%d\n",ans);
sort(f+1,f+ans+1,CMP);
for(int i=1;i<=ans;++i){
printf("%d %d\n",f[i].x,f[i].y);
}
return 0;
}