競プロ記録

問題を解いた際に自分の復習用として使ってます

CODE FESTIVAL 2017 qual B C問題 3 Steps

問題

code-festival-2017-qualb.contest.atcoder.jp

解説

辺を3本巡って到達できる頂点と辺を新たに結ぶので、2頂点間に奇数長のパスが存在すれば辺を結ぶことができます。 では奇数長のパスが存在するとはどのような時なのでしょうか。それは2分グラフであるかどうかに影響されます。 * 2分グラフである場合 辺を結ぶことができるのは色が異なる頂点間です。それは同色であると必ずパスの長さが偶数になるからです。 よって黒と白に塗り分けるとすると、黒の頂点数=b, 白の頂点数=wとすると bC1 * wC1 が結ぶことができる辺の数であり、すでに結ばれている辺の数Mを引いた値が答えになります。 * 2分グラフでない場合 必ず奇数長のサイクルが存在するので全ての2頂点間のパスの中に奇数長のパスが存在することになり、任意の2頂点間を辺で結ぶことができるためnC2-mが答えになります。

コード

#include <iostream>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
using namespace std;

const long long inf = 1e10;
const long long mod = 1e9+7;

typedef vector<vector<int> > G;
G graph;

int color[100050];

bool dfs(int u, int c){
    color[u] = c;
    for(int i=0; i<graph[u].size(); i++){
        int v = graph[u][i];
        if(color[v] == c){
            return false;
        }
        if(color[v] == 0 && !dfs(v, -c) ){
            return false;
        }
    }   
    return true;
}

int main(void){
    long long n, m;
    cin >> n >> m;
    graph = G(n);
    for(int i=0; i<m; i++){
        int x, y;
        cin >> x >> y;
        x--;
        y--;
        graph[x].push_back(y);
        graph[y].push_back(x);
    }
    long long B=0, W=0;
    if(dfs(0, 1)){
        for(int i=0; i<n; i++){
            if(color[i] == 1){
                B++;
            }else if(color[i] == -1){
                W++;
            }
        }
        cout << B*W - m << endl;
    }else{
        cout << ( (n*(n-1)) /2) - m << endl;
    }
    
    return 0;
}