题目大意:给定一个竞赛图,一些边没有指定方向,求一个指定方向的方案使竞赛图中三元环的数量最多
直接做不好做,我们考虑补集法
三个点之间如果不是三元环,那么一定有一个点有两条出边
于是我们可以得到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 跑费用流即可 每个点向所连边 */