概述
正解欧拉路,其实看完题解还是挺简单的,由于对欧拉路这种东西没怎么接触过,所以考试时没想出来,知识还是有漏洞啊。
另外这题的题解写的也不是很清楚(可能大佬作者觉得这是一道送分题……),首先判断联通(注意是边联通,即使是有一个点孤立也不会影响方案数),可以用dfs或并查集,注意dfs有一个坑点,不要直接就从1开始搜,因为1可能是那个被孤立的点。然后就可以求方案数了:
将无向图拆成双向边,显然每个点的度为偶数,是欧拉路,那么问题就转化成了从中去掉两条边使其仍然是欧拉路,题目中特别提醒了自环,所以分三种情况:
1.去掉两个自环,显然还是欧拉路,ans+=(num)*(num-1)/2;然而我一开始忘了除二(之前犯过的错误,该打)。
2.去掉一个自环和一条普通边,自环显然没问题,但是去掉普通边之后仍然是欧拉路吗?可以从去掉的那条边的反边起点开始走过去,那么每个点的度数仍然为偶数,仍然为欧拉路,ans+=num*(m-num);
3.剩下去掉普通边的情况了,怎么去才合法呢?去掉一个点的一条入边和一条出边,那么显然仍然是欧拉路,证明同上。去掉其他边呢?并不满足题意。所以ans+=$C_{du_i}^{2}$。
#include<iostream>
#include<cstdio>
#define MAXN 100100
#define int LL
#define LL long long
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
struct edge
{
int u,v,nxt;
#define u(x) ed[x].u
#define v(x) ed[x].v
#define n(x) ed[x].nxt
}ed[MAXN*4];
int first[MAXN],num_e;
#define f(x) first[x]
int n,m;
LL C[500010][5];
void get_C()
{
C[0][0]=1;
for(int i=1;i<=500000;i++)
{
C[i][0]=1;
for(int j=1;j<=min(i,4);j++)
C[i][j]=C[i-1][j]+C[i-1][j-1];
}
}
bool v[MAXN],ve[MAXN*4];
void pd(int x,int fa)
{
v[x]=1;
for(int i=f(x);i;i=n(i))
{
ve[i]=1;
if(v(i)!=fa&&!v[v(i)])pd(v(i),x);
}
}
int num,ans;
int du[MAXN];
inline int read();
inline void add(int u,int v);
signed main()
{
get_C();
n=read(),m=read();int a,b;
for(int i=1;i<=m;i++)
{
a=read(),b=read();
add(a,b);add(b,a);
if(a==b)num++;
else du[a]++,du[b]++;
}
for(int i=1;i<=n;i++)if(du[i]){pd(i,0);break;}
for(int i=1;i<=num_e;i++)if(!ve[i]){puts("0");return 0;}
ans+=num*(num-1)/2;
ans+=num*(m-num);
for(int i=1;i<=n;i++)
ans+=C[du[i]][2];
cout<<ans<<endl;
}
inline void add(int u,int v)
{
++num_e;
u(num_e)=u;
v(num_e)=v;
n(num_e)=f(u);
f(u)=num_e;
}
inline int read()
{
int s=0;char a=getchar();
while(a<'0'||a>'9')a=getchar();
while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();}
return s;
}
转载于:https://www.cnblogs.com/Al-Ca/p/11209321.html
最后
以上就是辛勤棒球为你收集整理的HZOJ 星际旅行的全部内容,希望文章能够帮你解决HZOJ 星际旅行所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复