Codeforces Round #311 (Div. 2) D. Vitaly and Cycle

18 篇文章 0 订阅
11 篇文章 0 订阅
  • 题目链接:http://codeforces.com/problemset/problem/557/D
  • 题意:给你包含n个顶点,m条边的不一定连通&&没有自环和重边的无向图,要你找到能够使得这个图中存在:(奇数长度&&顶点数>1 ) 的简单圈 所需添加边的最小数量t。并且找出添加t的方法数w
    • 禁止直接添加自环重边
    • 添加边的方法用所添加边的集合来区分,如果添加的边集相同则认为是同种方法
  • 算法:dfs,图论,组合数,数学
  • 思路:
    • 首先从边界条件开始思考
      • 当点的最大连边数=0 时,得t=3, w=n*(n-1)*(n-2)/6
      • 当点的最大连边数=1 时,得t=2, w=m*(n-2)
      • 当点的最大连边数>=2 时,用dfs判断图中是否有奇数圈,并将每个联通块的顶点陆续标记为1、2;
        • 若图中有奇数圈,则t=0, w=1
        • 若图中无奇数圈,则t=1, w=每个联通块∑ 【(在所有1号点中取两点的可能数)*(在所有2号点中取两点的可能数)】

#include <bits/stdc++.h>
#define pi acos(-1)
#define fastcin ios::base_sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const LL ll_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2*1e5 + 10;
const int mod = 1e9 + 7;

int ev[maxn], nxt[maxn], first[maxn];
int esum[maxn], node[maxn];
int cnt, cnt1=0, cnt2=0;

bool dfs_check(int u, int flag)
{
    if((node[u]=flag)==1) cnt1++; else cnt2++;
    for(int i=first[u]; i!=0; i=nxt[i]){
        int v=ev[i];
        if(node[v]==0){ if(dfs_check(v, 3-node[u])) return true; }
        else{
            if(node[u]==node[v]) return true;
        }
    }
    return false;
}


int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i=0; i<m; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        ev[++cnt]=v, nxt[cnt]=first[u], first[u]=cnt; esum[u]++;
        ev[++cnt]=u, nxt[cnt]=first[v], first[v]=cnt; esum[v]++;
    }
    int maxe = 0;
    for(int i=1; i<=n; i++) maxe = max(maxe, esum[i]);
    if(maxe==0) printf("3 %I64d\n", n*(n-1ll)*(n-2)/6);
    else if(maxe==1) printf("2 %I64d\n", m*(n-2ll));
    else {
        int i=1;
        LL ans=0;
        for(i=1; i<=n; i++)if(!node[i]){
            if(cnt1=cnt2=0, dfs_check(i, 1)) break;
            ans += cnt1*(cnt1-1ll)/2 + cnt2*(cnt2-1ll)/2;
        }
        if(i<=n) printf("0 1\n");
        else printf("1 %I64d\n", ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值