zoukankan      html  css  js  c++  java
  • CF1264E. Beautiful League

    【题目链接】https://codeforces.com/contest/1264/problem/E

    【题解】

    考虑三元环的数量如何计算。

    由于是完全有向图(即竞赛图),分别考虑每三个点会不会构成三元环。

    不难发现,三个点若不构成三元环一定存在且仅存在一个点出度为 $2$(入度同理)。

    因此考虑计算不构成三元环的三个点数量,即 $sum_{i=1}^{n} C_{deg_i}^{2}$(其中 $deg_i$ 为出度/入度)。

    因此总三元环个数为 $C_{n}^{3}-sum_{i=1}^{n} C_{deg_i}^{2}$。

    考虑给每条边定向会对三元环个数造成什么影响。

    显然定向会使其中一个点的度数增加。

    根据公式 $C_{k+1}^{2}-C_{k}^{2}=k$,定向会使答案减少点的度数个三元环。

    我们考虑本题的限制:每条边都一定要定向,不同方向会造成不同贡献,要求贡献最小(即三元环个数最大)。

    这是一个最小费用最大流的模型。考虑如何建图。

    首先 $S$ 向每条边代表的点连边,流量为 $1$,费用为 $0$,表示必须选择。

    其次每条边代表的点向边的两端点连边,流量为 $1$,表示两个方向需要选择一个方向。

    考虑费用如何计算。注意到当度数增加时,边的贡献也会改变。但任意时刻连向同一个点的边贡献相同。

    考虑经典做法——拆点。将每个点拆成两个,分别连流量为 $1$,费用为 $deg_i,deg_i+1,deg_i+2,...$ 的边即可。

    同时拆完后的后面的点往 $T$ 连流量为 $n$(其实并不会到 $n$,最多到 $n-deg_i-1$,上方拆点间连边同理),费用为 $0$ 的边。

    同时上述边向点连边的费用为 $0$。建图跑最小费用最大流即可。

    输出方案同一般费用流,判断满流情况。

     1 #include<bits/stdc++.h>
     2 const int inf=1<<30;
     3 const int maxn=100000;
     4 const int maxm=500000;
     5 struct Flow
     6 {
     7     int n,h[maxn],cnt=1,S,T,dis[maxn],fr[maxn];
     8     bool vis[maxn];
     9     struct edge { int v,nxt,f,w; } e[maxm];
    10     inline void addedge ( int u,int v,int f,int w )
    11     {
    12         e[++cnt].nxt=h[u];e[h[u]=cnt].v=v;e[cnt].f=f;e[cnt].w=w;
    13         e[++cnt].nxt=h[v];e[h[v]=cnt].v=u;e[cnt].f=0;e[cnt].w=-w;
    14     }
    15     inline bool spfa_min ( void )
    16     {
    17         for ( int i=1;i<=n;i++ ) vis[i]=false,fr[i]=0,dis[i]=inf;
    18         std::queue<int> q;dis[S]=0;q.push(S);vis[S]=true;
    19         while ( !q.empty() )
    20         {
    21             int u=q.front();q.pop();vis[u]=false;
    22             for ( int i=h[u];i;i=e[i].nxt ) if ( e[i].f and dis[e[i].v]>dis[u]+e[i].w )
    23             {
    24                 dis[e[i].v]=dis[u]+e[i].w;fr[e[i].v]=i;
    25                 if ( !vis[e[i].v] ) q.push(e[i].v),vis[e[i].v]=true;
    26             }
    27         }
    28         return dis[T]!=inf;
    29     }
    30     inline int mincost ( void )
    31     {
    32         int ans=0;
    33         while ( spfa_min() )
    34         {
    35             int flow=inf;
    36             for ( int i=T;i!=S;i=e[fr[i]^1].v ) flow=std::min(flow,e[fr[i]].f);
    37             ans+=dis[T]*flow;
    38             for ( int i=T;i!=S;i=e[fr[i]^1].v ) e[fr[i]].f-=flow,e[fr[i]^1].f+=flow;
    39         }
    40         return ans;
    41     }
    42 } Gmin;
    43 int n,m,N,G[200][200],ans[200][200],d[200];
    44 signed main()
    45 {
    46     scanf("%d%d",&n,&m);
    47     for ( int i=1,u,v;i<=m;i++ ) scanf("%d%d",&u,&v),d[u]++,ans[u][v]=1,G[u][v]=G[v][u]=-1;
    48     N=n<<1;Gmin.S=++N;Gmin.T=++N;
    49     for ( int i=1;i<n;i++ ) for ( int j=i+1;j<=n;j++ ) if ( ~G[i][j] )
    50     {
    51         G[i][j]=G[j][i]=++N;
    52         Gmin.addedge(Gmin.S,G[i][j],1,0);
    53         Gmin.addedge(G[i][j],i,1,0);
    54         Gmin.addedge(G[i][j],j,1,0);
    55     }
    56     int Ans=n*(n-1)*(n-2)/6;
    57     for ( int i=1;i<=n;i++ )
    58     {
    59         Ans-=d[i]*(d[i]-1)/2;
    60         for ( int j=1;j<=n;j++ ) Gmin.addedge(i,i+n,1,d[i]+j-1);
    61     }
    62     for ( int i=1;i<=n;i++ ) Gmin.addedge(i+n,Gmin.T,n,0);
    63     Gmin.n=N;Gmin.mincost();
    64     for ( int i=1;i<n;i++ ) for ( int j=i+1;j<=n;j++ ) if ( ~G[i][j] )
    65         for ( int k=Gmin.h[G[i][j]];k;k=Gmin.e[k].nxt ) if ( Gmin.e[k].v!=Gmin.S and !Gmin.e[k].f ) ans[Gmin.e[k].v][i+j-Gmin.e[k].v]=true;
    66     for ( int i=1;i<=n;i++,puts("") ) for ( int j=1;j<=n;j++ ) putchar(ans[i][j]?'1':'0');
    67     return 0;
    68 }
    CF1264E

    官方题解&$std$ 在此做法的基础上使用了更复杂的算法,类似模拟费用流的贪心。由于作者水平有限,并不会这种做法。具体请参见:https://codeforces.com/blog/entry/71995

  • 相关阅读:
    类加载器ClassLoader
    JAVA分别获取日期中的年、月、日
    sql 安全问题
    马尔科夫链
    触发器、锁、事务和事务控制
    索引、视图、存储过程、函数、游标
    字符集
    数据类型选择
    存储引擎
    错误:too many indices for array
  • 原文地址:https://www.cnblogs.com/RenSheYu/p/12245710.html
Copyright © 2011-2022 走看看