CF1264E

CF1264E - Beautiful League

题目大意

给定一张竞赛图,其中一些边已经确定

现在求确定剩余边的方向,使得最终图上三元环个数最大


分析

三元问题着实难以处理

考虑什么样的三个点((x,y,z))无法构成一个环:

三个点恰好存在一个点(x)得到两条入边,即(xleftarrow y,xleftarrow z)

此时无法构成环


于是问题转化为统计(x)的入度(ind_x),减少的三元环个数就是(sum inom{ind_i}{2})

考虑用网络流计算答案,每一条边((u,v))可以选择从(S)流向(u)或者(v)

一个点得到(i)的流量付出(inom{i}{2})的代价流出(T)

因此每个点向(T)(n-1)条流量为(1),代价分别为为(inom{j}{2}-inom{j-1}{2})的边

求满流最小费用即可,输出方案容易根据流量情况判断

复杂度为(O( ext{MCMF}(n^2,n^2))) 或者(O( ext{MCMF}(n,n^2)))

const int N=2e5+10,INF=1e9+10;

int n,m,S,T,V;
struct Edge{
	int to,nxt,w,c;
} e[N];
int head[N],ecnt=1;
void AddEdge(int u,int v,int w,int c){
	e[++ecnt]=(Edge){v,head[u],w,c};
	head[u]=ecnt;
}
void Link(int u,int v,int w,int c){ AddEdge(u,v,w,c),AddEdge(v,u,0,-c); }

int ans,dis[N];
char s[N];
int inq[N],pre[N],w[N];
int mk[110][110];

int main(){
	n=rd(),m=rd(),S=n+1,T=V=S+1;
	rep(i,1,n) rep(j,1,n-1) Link(i,T,1,j*(j-1)/2-(j-1)*(j-2)/2);
	memset(mk,-1,sizeof mk);
	while(m--) {
		int u=rd(),v=rd();
		if(u<v) mk[u][v]=1;
		else mk[v][u]=0;
	}
	rep(i,1,n) rep(j,i+1,n) {
		Link(S,++V,1,0);
		if(mk[i][j]!=0) Link(V,j,1,0);
		if(mk[i][j]!=1) Link(V,i,1,0);
	}
	while(1) {
		static queue <int> que;
		rep(i,1,V) dis[i]=INF;
		dis[S]=0,que.push(S),w[S]=INF;
		while(!que.empty()) {
			int u=que.front(); que.pop();
			inq[u]=0;
			for(int i=head[u];i;i=e[i].nxt) {
				int v=e[i].to,c=e[i].c;
				if(!e[i].w || dis[v]<=dis[u]+c) continue;
				dis[v]=dis[u]+c,w[v]=min(e[i].w,w[u]),pre[v]=i;
				if(!inq[v]) que.push(v),inq[v]=1;
			}
		}
		if(dis[T]==INF) break;
		int c=w[T]; ans+=dis[T]*c;
		for(int u=T;u!=S;u=e[pre[u]^1].to) e[pre[u]].w-=c,e[pre[u]^1].w+=c;
	}
	memset(mk,0,sizeof mk);
	rep(a,1,n) rep(b,a+1,n) {
		int u=++T;
		for(int i=head[u];i;i=e[i].nxt) if(e[i].to<=n && !e[i].w) {
			if(e[i].to==b) mk[a][b]=1;
			else mk[b][a]=1;
		}
	}
	rep(i,1,n) {
		rep(j,1,n) putchar(mk[i][j]+'0');
		puts("");
	}
}
原文地址:https://www.cnblogs.com/chasedeath/p/14756613.html