BZOJ2597 [Wc2007]剪刀石头布 【费用流】
2018-05-25 19:57
369 查看
题目链接
题解
orz思维差
既然是一张竞赛图,我们选出任意三个点都可能成环
总方案数为
\[{n \choose 3}\]
如果三个点不成环,会发现它们的度数是确定的,入度分别为\(2,1,0\),出度为\(0,1,2\)
所以一个点的任意两个入度,都会对答案产生一个负的贡献
所以三元环数量为
\[{n \choose 3} - \sum\limits_{i = 1}^{n} {inde[i] \choose 2}\]
我们要最大化三元环数目,就要最小化\(\sum\limits_{i = 1}^{n} {inde[i] \choose 2}\)
考虑建模,使用费用流
每条边可以将入度分给,也仅可以分配给两端点中的一个
我们就每条边建一个点,从\(S\)向每条边建出来的点连一条\((1,0)\)的边,表示能产生一个流量
然后该边的点向那两个端点分别连一条\((1,0)\)的边,表示能产生\(1\)个入度
然后考虑每产生一个入度的影响
考虑到
\[{x \choose 2} - {x - 1 \choose 2} = x - 1\]
所以每增加一个入度,使得入度为\(x\)时,会多产生\(x - 1\)个贡献
按照费用流的套路,我们对每个点每一种度数建一条到\(T\)的边(1,x - 1),表示消耗这么多三元环
按照费用流的性质,一定会优先选择权值较小的边,也就是逐层增加
建图时,还要考虑原来已有的边
然后就做完了
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<map> #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define mp(a,b) make_pair<int,int>(a,b) #define cls(s) memset(s,0,sizeof(s)) #define cp pair<int,int> #define LL long long int using namespace std; const int maxn = 11005,maxm = 100005,INF = 1000000000; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();} return out * flag; } int h[maxn],ne = 1; struct EDGE{int from,to,nxt,f,w;}ed[maxm]; inline void build(int u,int v,int f,int w){ ed[++ne] = (EDGE){u,v,h[u],f,w}; h[u] = ne; ed[++ne] = (EDGE){v,u,h[v],0,-w}; h[v] = ne; } int q[maxn * 10],head,tail; int p[maxn],vis[maxn],S,T; int d[maxn],minf[maxn]; int mincost(){ int cost = 0,flow = 0; while (true){ for (int i = S; i <= T; i++) d[i] = minf[i] = INF,vis[i] = false; d[S] = 0; q[head = tail = 0] = S; int u; while (head <= tail){ u = q[head++]; vis[u] = false; Redge(u) if (ed[k].f && d[u] + ed[k].w < d[to = ed[k].to]){ minf[to] = min(minf[u],ed[k].f); p[to] = k; d[to] = d[u] + ed[k].w; if (!vis[to]) q[++tail] = to,vis[to] = true; } } if (d[T] == INF) break; flow += minf[T]; cost += d[T] * minf[T]; u = T; while (u != S){ ed[p[u]].f -= minf[T]; ed[p[u] ^ 1].f += minf[T]; u = ed[p[u]].from; } } return cost; } int n,G[105][105],de[105],N,a[maxn],b[maxn]; int main(){ n = read(); REP(i,n) REP(j,n){ G[i][j] = read(); if (i == j) continue; if (!G[i][j]) de[i]++; else if (G[i][j] == 2 && i < j) N++,a = i,b = j; } S = 0; T = N + n + 1; REP(i,N) build(S,i,1,0),build(i,N + a[i],1,0),build(i,N + b[i],1,0); REP(i,n){ for (int j = de[i] + 1; j <= n; j++) build(N + i,T,1,j - 1); } int ans = n * (n - 1) * (n - 2) / 6; REP(i,n) if (de[i] > 1) ans -= de[i] * (de[i] - 1) / 2; ans -= mincost(); printf("%d\n",ans); REP(i,N){ Redge(i) if ((to = ed[k].to) > N && !ed[k].f){ if (to - N == a[i]) G[a[i]][b[i]] = 0,G[b[i]][a[i]] = 1; else G[a[i]][b[i]] = 1,G[b[i]][a[i]] = 0; break; } } for (int i = 1; i <= n; i++,puts("")){ for (int j = 1; j <= n; j++){ printf("%d",G[i][j]); if (j < n) putchar(' '); } } return 0; }
相关文章推荐
- 【BZOJ2597】【Wc2007】剪刀石头布 费用流,没写zkw卡时过
- BZOJ 2597: [Wc2007]剪刀石头布|费用流
- bzoj1449: [JSOI2009]球队收益&&bzoj2597: [Wc2007]剪刀石头布
- bzoj2597: [Wc2007]剪刀石头布
- Bzoj2597 [Wc2007]剪刀石头布
- bzoj2597: [Wc2007]剪刀石头布
- 【BZOJ2597】[Wc2007]剪刀石头布 最小费用流
- 【BZOJ2597】【WC2007】剪刀石头布
- BZOJ 2597 WC2007 剪刀石头布 费用流
- [bzoj2597][WC2007]剪刀石头布
- 【WC2007】bzoj2597 剪刀石头布
- [BZOJ]2597: [Wc2007]剪刀石头布 费用流
- 2597: [Wc2007]剪刀石头布 费用流
- BZOJ 2597: [Wc2007]剪刀石头布 费用流
- 【BZOJ】【P2597】【Wc2007】【剪刀石头布】【题解】【费用流】
- BZOJ 2597: [Wc2007]剪刀石头布 费用流
- BZOJ 2597 WC2007 剪刀石头布 费用流
- [BZOJ2597][Wc2007]剪刀石头布(费用流)
- [Wc2007]剪刀石头布
- BZOJ 2597 [Wc2007]剪刀石头布