1. 程式人生 > >【BZOJ 2503】相框 圖論+討論

【BZOJ 2503】相框 圖論+討論

相互 == 輸出 信息 只需要 false log logs 基本知識

這道題目就是考驗了一下圖論基本知識與對可愛的代碼實現的應對能力。

我們先分析題幹信息。我們要形成相框,那麽所有的點的度為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; }

【BZOJ 2503】相框 圖論+討論