zoukankan      html  css  js  c++  java
  • CF #311 D. Vitaly and Cycle 加最少边形成奇圈

    题目链接:http://codeforces.com/problemset/problem/557/D

    大意 给出一个未必联通的无向图(点数至少为3),问最少加多少边可以形成一个奇圈,以及这样做的方案有多少种。

    首先如果是一张没有边的图,那么直接就是需要加三条边,有C(n,3)种方式。

    接着,判断这张图每一个联通块是否是一个二分图,因为二分图是一定没有奇圈的。如果有联通块不是二分图,那么也就是意味着存在奇圈,这样的话需要加0条边,方式为1种。

    接下去还需要分两种情况讨论

    1.如果所有的联通块都只有1个或者2个点,则至少需要加2条边,方式为所有点数为2的联通块随便选择一个其他的点加2条边,故统计所有点数为2的联通块数量。

    2.存在至少包含3个点的联通块,注意,此时已经排除了联通块不是二分图的情况,所以也即联通块一定是二分图。对于二分图,连接x部和y部的边是不会形成奇圈的,这种情况下只需要连接一条相同部之间的边即可。所以方案数为对于所有至少包含3个点的联通块,计算x部和y部点数,对答案累加上 C(cntx,2)+C(cnty,2)

     1 #include <iostream>
     2 #include <vector>
     3 #include <algorithm>
     4 #include <string>
     5 #include <string.h>
     6 #include <stdio.h>
     7 #include <math.h>
     8 #include <stdlib.h>
     9 #include <queue>
    10 #include <stack>
    11 #include <map>
    12 #include <set>
    13 
    14 using namespace std;
    15 
    16 const int N=1e5+100;
    17 
    18 vector<int> edge[N];
    19 bool vis[N];
    20 int col[N];
    21 bool found=false;
    22 int cnt[2];
    23 void dfs(int u,int c) {
    24     vis[u]=true;
    25     col[u]=c;
    26     cnt[c]++;
    27     for (int i=0;i<edge[u].size();i++) {
    28         int v=edge[u][i];
    29         if (vis[v]&&col[v]==c) {
    30             found=true;
    31         }
    32         if (vis[v]) continue;
    33         dfs(v,c^1);
    34     }
    35 }
    36 int main(){
    37     int n,m;
    38     scanf("%d %d",&n,&m);
    39     for (int i=1;i<=m;i++) {
    40         int u,v;
    41         scanf("%d %d",&u,&v);
    42         edge[u].push_back(v);
    43         edge[v].push_back(u);
    44     }
    45     if (m==0) {
    46         long long ret=1LL*n*(n-1)*(n-2)/6LL;
    47         cout<<3<<" "<<ret<<endl;
    48     }
    49     else {
    50         found=false;
    51         bool three=false;
    52         long long retThree=0;
    53         int cnt2=0;
    54         for (int i=1;i<=n&&!found;i++) {
    55             if (vis[i]) continue;
    56             cnt[0]=cnt[1]=0;
    57             dfs(i,0);
    58             if (cnt[0]+cnt[1]>=3){
    59                 three=true;
    60                 retThree+=1LL*cnt[0]*(cnt[0]-1)/2LL+1LL*cnt[1]*(cnt[1]-1)/2LL;
    61             }
    62             else if (cnt[0]+cnt[1]==2)
    63                 cnt2++;
    64         }
    65         if (found) {
    66             cout<<0<<" "<<1<<endl;
    67         }
    68         else if (three){
    69             cout<<1<<" "<<retThree<<endl;
    70         }
    71         else {
    72             long long ret=1LL*cnt2*(n-2);
    73             cout<<2<<" "<<ret<<endl;
    74         }
    75     }
    76     return 0;
    77 }
    View Code
  • 相关阅读:
    重构原则
    【重构:改善既有代码的设计】读书笔记——开篇
    C#值参数和引用参数
    使用Aspose.Cells利用模板导出Excel(C#)
    在MVC中使用rdlc格式的报表
    程序员如何高效学习
    IT 圈里有哪些经常被读错的词?
    VS2017生成解决方案报错,提示对路径的访问被拒绝
    JavaScript中的数值转换
    Xadmin的配置及使用
  • 原文地址:https://www.cnblogs.com/micrari/p/5309329.html
Copyright © 2011-2022 走看看