Solution to a problem - Star Trek (Euler Road)

Solution to a problem - Star Trek (Euler Road)

A very clever way Euler problems, but also pay attention to details


Face questions

Description
title face hidden

Input
a map

Output
An integer representing the lowest cost

in.1
5 4
1 2
1 3
1 4
1 5

out.1
6

Data range and Conventions

To 100% of the data, n, m <= 1e5, other hidden

Thinking

The main idea
was meaning of the questions, we just need to double each side, and then select two different sides on all sides, remove it, or if they meet the Euler Euler way, you can get an essentially different program.

It divided into two parts:

1. China Unicom judgment, if none, the program number is certainly 0
2 classification statistical processing contributions

deal with:

1. FIG Analyzing Unicom to build a run time dfs each edge marking, may not be used to build FIG disjoint-set, both methods are O (n)

2. Well, the key here.

Premise: After the double side, the degree of all points becomes even.
Cndition1: remove two loopback. Due to the impact from the ring on a point is an even number, select any two loopback deleted, so always satisfy Euler tour. = C + ANS (2, m)
Cndition2: Remove a + a loopback side. Due to the impact from the ring on a point is an even number, ignored, and the degree of one side two points becomes an odd number, so always satisfy Euler Road. ans + = X number of paths from the number of rings
Cndition3: delete the two sides, unable to meet the conditions of Euler, Euler way to ensure that meet the conditions, select the two sides must have one thing in common. So for each point of the initial degree (not double)> = 2, statistical contribution. ans + = Σ C (2, du [i]).

Details:
1. If using dfs sentenced Unicom, pay attention to the cumulative number of times to exit the ring, otherwise burst stack.
2. Because the same can not be deleted after the heavy side doubled, after the above-mentioned practices delete diagram remain Unicom.

DFS version (from ssw02)

#include<bits/stdc++.h>
using namespace std ;
#define ll long long
const int MAXN = 100005 ;
inline int read(){
    int s=0 ;char g=getchar(); while(g>'9'||g<'0')g=getchar() ; 
    while( g>='0'&&g<='9')s=s*10+g-'0',g=getchar() ; return s ;
}
ll ans = 0LL , sum = 0LL , cnt = 0LL , du[ MAXN ] ;
int  N , M , head[ MAXN ] , to[ MAXN*2 ] , nex[ MAXN*2 ] , tot = 1 , vis[ MAXN ];//边 自环 
bool  used[ MAXN*2 ] , key ;
void  add( int x , int y ){
    to[ ++tot ] = y , nex[ tot ] = head[ x ] , head[ x ] = tot ;
}
void  check(){
    for( int i = 2 ; i <= tot ; ++i )
        if( !used[ i ] ){
            key = true ; break ;
        }
}
void  dfs( int u , int fa ){
    vis[ u ]++ ;
    if( vis[ u ] > 10 )return ;//平时开大点,这里数据水
    for( int i = head[ u ] ; i ; i = nex[ i ] ){
        used[ i ] = true ;
        if( to[i] == fa || to[ i ] == u )continue ;
        dfs( to[i] , u ) ;
    }
}
int main(){
    N = read() , M = read() ; int  m1 , m2 ;
    for( int i = 1 ; i <= M ; ++i ){
        m1 = read() , m2 = read() ; add( m1 , m2 ) , add( m2 , m1 ) ;
        if( m1 != m2 )
            sum++ , du[ m1 ]++ , du[ m2 ]++ ;
        else cnt++ ;
    }
    for( int i = 1 ; i <= N ; ++i )
        if( head[ i ] ){dfs( i , i )  ; break ;}
    check();
    if( key ){ printf("0");return 0 ;}
    if( cnt >= 2 )
        ans = (ll)cnt*(ll)(cnt-1LL)/2LL ;
    if( cnt >= 1 && sum >= 1 )
        ans += (ll)sum*cnt ;
    if( sum >= 2 )
        for( int i = 1 ; i <= N ; ++i )
            ans += ( (ll)du[i]*(du[i]-1LL) )/2LL ;
    cout<<ans ;
} 

Disjoint-set version (std)

#include<cstdio>
#include<iostream>
using namespace std;
#define maxn 1000010
int fa[maxn],siz[maxn];
int findfa(int p)
{
    if(fa[p]!=p) fa[p]=findfa(fa[p]);
    return fa[p];
}
void uni(int p,int q)
{
    p=findfa(p),q=findfa(q);
    if(p!=q)
    {
        fa[p]=q;
        siz[q]+=siz[p];
    }
}
int n,m,l[maxn],r[maxn];
int du[maxn],sig;
bool v[maxn];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++) fa[i]=i,siz[i]=1;
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&l[i],&r[i]);
        uni(l[i],r[i]);
        if(l[i]!=r[i])
        {
            du[l[i]]++;
            du[r[i]]++;
        }
        else sig++;
    }
    int lst=findfa(l[1]);
    for(int i=2; i<=m; i++)
        if(findfa(l[i])!=lst) {lst=-1; break;}
    if(lst==-1) cout<<0<<endl;
    else
    {
        long long ans=0;
        ans+=1ll*sig*(sig-1)/2;
        ans+=1ll*sig*(m-sig);
        for(int i=1; i<=n; i++)
            ans+=1ll*du[i]*(du[i]-1)/2;
        cout<<ans<<endl;
    }
    return 0;
}

If insufficient, please indicate Gangster

Guess you like

Origin www.cnblogs.com/ssw02/p/11409002.html