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;
}