問題へのソリューション - スタートレック(オイラーの道)

問題へのソリューション - スタートレック(オイラーの道)

オイラーの問題は非常に巧妙な方法が、また、細部に注意を払います


フェイス質問

説明
タイトル顔が隠れて

入力
マップ

出力
最小のコストを表す整数

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

out.1
6

データ範囲と表記

データの100%に、N、M <= 1E5は、他の隠れ

考え

主なアイデアは、
質問の意味された、私たちはそれぞれの側を倍増して、すべての側面上の2つの異なる側面を選択し、それを削除する必要がある、またはそれらはオイラーオイラーの道を満たしている場合、あなたは本質的に異なる得ることができますプログラム。

これは、2つの部分に分け:

1.中国聯通の判断は、どれもあれば、プログラム番号は確かに0である
2分類統計処理貢献

治療:

ランタイムを構築するユニコムの分析1.図は、図の互いに素なセットを構築するために使用されなくてもよい、マーキング各エッジをDFS、両方の方法は、O(N)

2.さて、キーここに。

前提は:ダブルサイド後は、すべてのポイントの度合いが均一になります。
Cndition1: 2つのループバックを削除します。ポイントのリングからインパクトまでの偶数である、削除された任意の二つのループバックを選択するので、常にオイラーツアーを満たします。= C + ANS(2、M)
Cndition2: +ループバック側を削除します。点にリングからの衝撃に無視偶数であり、片側2点の次数が奇数となるので、常にオイラー道を満たします。リングの数からパスのANS + = X数
Cndition3:それは一つの共通点を持っていなければならない2つの辺を選択し、条件を満たしていることを確認するためにオイラー、オイラー道の条件を満たすことができない二つの側面を、削除します。そう初期度の各点について(ダブルない)> = 2、統計的寄与。ANS + =ΣC(2、デュ[I])。

詳細:
1.使用してDFSがユニコムを宣告した場合、リング、それ以外の場合はバーストスタックを終了した累積回数に注意を払います。
重い側が倍増した後に同じを削除することができないので、上記の実践後の図を削除2.ユニコムのままです。

DFSバージョン(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 ;
} 

互いに素セット版(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;
}

不十分な場合は、ギャングを明記してください

おすすめ

転載: www.cnblogs.com/ssw02/p/11409002.html