• BZOJ2597 [Wc2007]剪刀石头布 【费用流】


    题目链接

    BZOJ2597

    题解

    orz思维差

    既然是一张竞赛图,我们选出任意三个点都可能成环
    总方案数为

    [{n choose 3} ]

    如果三个点不成环,会发现它们的度数是确定的,入度分别为(2,1,0),出度为(0,1,2)
    所以一个点的任意两个入度,都会对答案产生一个负的贡献

    所以三元环数量为

    [{n choose 3} - sumlimits_{i = 1}^{n} {inde[i] choose 2} ]

    我们要最大化三元环数目,就要最小化(sumlimits_{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[N] = i,b[N] = 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
    ",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;
    }
    
    
  • 相关阅读:
    CodeForces
    bzoj 2257: [Jsoi2009]瓶子和燃料
    【NOIP2009】Hankson 的趣味题
    51Nod 1203 JZPLCM
    bzoj 3751: [NOIP2014]解方程
    UOJ #11. 【UTR #1】ydc的大树
    Tenka1 Programmer Contest D
    bzoj 5000: OI树
    bzoj 1407: [Noi2002]Savage
    bzoj 3551: [ONTAK2010]Peaks加强版
  • 原文地址:https://www.cnblogs.com/Mychael/p/9090455.html
Copyright © 2020-2023  润新知