题目大意:给定一个竞赛图,一些边没有指定方向,求一个指定方向的方案使竞赛图中三元环的数量最多
直接做不好做,我们考虑补集法
三个点之间如果不是三元环,那么一定有一个点有两条出边
于是我们可以得到ans=C(n,3)-ΣC(degree[x],2)
于是我们考虑费用流的模型
每条边化为一个点
从源点向每个点连n-1条边,流量为1,费用为0,1,...,n-2
一条边如果可以或必须成为一个点的出边 那么就从这个点出发向这条边连一条流量为1,费用为零的边
每条边向汇点连一条流量为1,费用为零的边
跑最小费用最大流即可
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 11000
#define S 0
#define T 10999
#define INF 0x3f3f3f3f
using namespace std;
struct abcd{
int to,f,cost,next;
}table[1001001];
int head[M],tot=1;
int n,cnt,ans,map[110][110],edge[110][110];
void Add(int x,int y,int f,int cost)
{
table[++tot].to=y;
table[tot].f=f;
table[tot].cost=cost;
table[tot].next=head[x];
head[x]=tot;
}
void Link(int x,int y,int f,int cost)
{
Add(x,y,f,cost);
Add(y,x,0,-cost);
}
bool Edmons_Karp()
{
static int q[65540],f[M],from[M],cost[M];
static unsigned short r,h;
static bool v[M];
int i;
memset(cost,0x3f,sizeof cost);
q[++r]=S;f[S]=INF;cost[S]=0;f[T]=0;
while(r!=h)
{
int x=q[++h];v[x]=0;
for(i=head[x];i;i=table[i].next)
if( table[i].f && cost[x]+table[i].cost<cost[table[i].to] )
{
cost[table[i].to]=cost[x]+table[i].cost;
f[table[i].to]=min(f[x],table[i].f);
from[table[i].to]=i;
if(!v[table[i].to])
v[table[i].to]=1,q[++r]=table[i].to;
}
}
if(!f[T]) return false;
ans-=cost[T]*f[T];
for(i=from[T];i;i=from[table[i^1].to])
table[i].f-=f[T],table[i^1].f+=f[T];
return true;
}
int main()
{
//freopen("hand.in","r",stdin);
//freopen("hand.out","w",stdout);
int i,j;
cin>>n;cnt=n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&map[i][j]);
for(i=1;i<=n;i++)
for(j=0;j<=n-2;j++)
Link(S,i,1,j);
for(i=1;i<=n;i++)
for(j=1;j<i;j++)
{
Link(++cnt,T,1,0);
if(map[i][j]==0||map[i][j]==2)
Link(i,cnt,1,0),edge[j][i]=tot-1;
if(map[i][j]==1||map[i][j]==2)
Link(j,cnt,1,0),edge[i][j]=tot-1;
}
ans=n*(n-1)*(n-2)/6;
while( Edmons_Karp() );
cout<<ans<<endl;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j) printf("0%c",j==n?'\n':' ');
else printf("%d%c",!edge[i][j]||table[edge[i][j]].f?0:1,j==n?'\n':' ');
}
return 0;
}
/*
S 0
每个点变为图上的一个点 1~n
每条边变为图上的一个点 n+1~n+(n*(n-1)/2)
T 10999
S向每个点连n-1条边 流量为1 费用为0~n-2
每条边变成的点向T连边 流量为1 费用为0
每个点向所有出边化为的点连边 流量为1 费用为0
跑费用流即可
每个点向所连边
*/