NOIP2018三校聯考--電壓機制(voltage)
阿新 • • 發佈:2018-12-16
很容易發現與奇環和偶環有關,但是仔細想清楚和怎麼用程式實現還是很難的
但是我們dfs一邊後,會發現能形成環的邊都變成了返祖邊
而且這些返祖邊對於答案大部分情況下都沒有貢獻
偶環上的邊都不能做出貢獻,當且僅當一條邊被所有奇環包含時才能做出貢獻
有兩個性質如下:
性質1:如果有超過兩個奇環,則所有非樹邊都沒有貢獻,否則有1的貢獻
性質2:兩條特殊邊組合也不會對答案產生任何貢獻
情況1: 情況2: 情況3:
列舉後就可以證明以上的規律
那麼每條返祖邊都是修改通往根節點的一條鏈,就可以用查分非常簡單的實現
程式碼如下:(昨天被STL迷住了,所以寫了又慢又醜的迭代器STL程式碼)
#include<bits/stdc++.h> using namespace std; vector <pair<int,int> > edge[400005]; int vis[400005],n,m,one[400005],two[400005],ans,depth[400005]; int shu1,shu2,sum1,sum2,pd[400005],father[400005]; void dfs1(int x) { pd[x]=1; for(vector <pair<int,int> > ::iterator it=edge[x].begin(),ed=edge[x].end();it!=ed;it++) { int y=it->second; if(vis[it->first]) continue; vis[it->first]=vis[(it->first)^1]=1; if(pd[y]) { if((depth[x]&1)==(depth[y]&1)) { one[x]++; one[y]--; sum1++; } else { two[x]++; two[y]--; sum2++; } } else { father[y]=it->first; depth[y]=depth[x]+1; dfs1(y); } } } void dfs2(int x) { for(vector <pair<int,int> > ::iterator it=edge[x].begin(),ed=edge[x].end();it!=ed;it++) { int y=it->second; if(father[y]==it->first) { dfs2(y); one[x]+=one[y]; two[x]+=two[y]; } } } int main() { freopen("voltage.in","r",stdin); freopen("voltage.out","w",stdout); cin>>n>>m; for(int i=1;i<=m;i++) { scanf("%d%d",&shu1,&shu2); edge[shu1].push_back(make_pair(i*2,shu2)); edge[shu2].push_back(make_pair(i*2+1,shu1)); } depth[1]=1; dfs1(1); dfs2(1); for(int i=1;i<=n;i++) { if(father[i]&&one[i]==sum1&&two[i]==0) ans++; } if(sum1==1) ans++; cout<<ans; return 0; }