【BZOJ 2503】相框 图论+讨论
这道题目就是考验了一下图论基本知识与对可爱的代码实现的应对能力。
我们先分析题干信息。我们要形成相框,那么所有的点的度为2(参与的点),那么所有度大于2的点都需要熔断,而且一次完成所有关于这个点的熔断,也就是说将一个焊点变成一堆度小于等于2的焊点,然后我们发现我们这个时候只需要焊接了。由此可知我们熔断的次数是一定的(除了简单环,度为2的点不需要熔断,因为这样做只会做负贡献),就好是熔断所有度大于2的点以及独立简单环,那么现在我们要做的就是让焊接次数最少,也就是分成较少的链。对于独立欧拉图不用讲就是一条,对于存在奇数入度的点的图,我们观察,他最少的条数就是奇点的个数除二,因为所有链(相互独立不可合并)的两端的点一定是奇数点(如果是偶数点意味着有其他端点对着他那么这条路径就可以删去了),然后我们再看他的可行性我们如果用奇数点除二的边将这些点互相连接,就会存在欧拉图那么我们在去掉我们加上的边就会的到那些条路径。
于是我们找联通块,(特别的如果我们的图是一个简单环就输出0,如果我们的图是一个欧拉图我们就是只熔断),对于欧拉图联通块我们化成一条链,(特别的对于简单环我们手动熔断),对半欧拉图我们把它化成奇数点除二条链。
于此注意细节便可A。
#include <cstdio> #include <cstring> const int N=1010; const int M=100010; struct V{ int to,next; }c[M<<2]; int head[M<<1],t; inline void add(int x,int y){ c[++t].to=y,c[t].next=head[x],head[x]=t; } int n,m,sz,size[M<<1]; bool v[M<<1]; inline bool judge(){ if(n!=sz)return false; for(int i=1;i<=n;++i) if(size[i]!=2)return false; return true; } void dfs(int x,int &sum,int &is){ if(v[x])return; v[x]=true,sum+=(x>n||(size[x]&1))?1:0; if(size[x]!=2)is=0; for(int i=head[x];i;i=c[i].next) dfs(c[i].to,sum,is); } inline int get(){ int ret=0,first=-1,sum=0,ou=-1; for(int i=1;i<=sz;++i) if(v[i]==false&&(size[i]!=0||i>n)){ int num=0,is=1;dfs(i,num,is); ++sum; if(num==0)ret+=1+is; else ret+=num>>1; if(first==-1)first=num,ou=is; } for(int i=1;i<=n;++i) if(size[i]>2) ++ret; if(sum==1&&first==0&&ou==1)ret=0; if(sum==1&&first==0)ret--; return ret; } int main(){ scanf("%d%d",&n,&m),sz=n; for(int i=1,x,y;i<=m;++i){ scanf("%d%d",&x,&y); if(x)size[x]++; else x=++sz; if(y)size[y]++; else y=++sz; add(x,y),add(y,x); } printf("%d",get()); return 0; }
苟利国家生死以, 岂因祸福避趋之。