2020牛客多校第1场I-1 or 2一般图最大匹配带花树
??鏈接:https://ac.nowcoder.com/acm/contest/5666/I
Bobo has a graph with n vertices and m edges where the i-th edge is between the vertices ai? and bi?. Find out whether is possible for him to choose some of the edges such that the i-th vertex is incident with exactly d[i]?edges.
題目大意:給了一個(gè)無向圖,問能否選擇一些邊,使得每個(gè)點(diǎn)的度數(shù)都為d[i];
思路:拆點(diǎn)拆邊完 就是跑一般圖的最大匹配了,看能否匹配成功。
可能你會(huì)在圖中看到兩個(gè)3 實(shí)際上式將3 這個(gè)點(diǎn)按照度d 3 = 2 拆分成3和3’
?4、5、6、7這幾個(gè)出現(xiàn)的點(diǎn)可能會(huì)疑惑,實(shí)際上就是將邊拆分成兩個(gè)部分,即將1-3邊拆分成4、5,而4與1是有關(guān)的、5與3是有關(guān)以此類推。
拆完之后 圖是這樣的,然后直接跑帶花樹
#include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <queue> #include <string> #include <cstring> #include <map> #include <stack> #include <set> #include <cstdlib> #define INF 0x3f3f3f3f3f3f3f3f #define inf 0x3f3f3f3f #define FILL(a,b) (memset(a,b,sizeof(a))) #define re register #define lson rt<<1 #define rson rt<<1|1 #define lowbit(a) ((a)&-(a)) #define ios std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0); #define fi first #define rep(i,n) for(int i=0;(i)<(n);i++) #define rep1(i,n) for(int i=1;(i)<=(n);i++) #define se second #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define ac cout<<ans<<"\n" #define F(x) ((x)/3+((x)%3==1?0:tb)) #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll,ll> pii; int dx[4]= {-1,1,0,0},dy[4]= {0,0,1,-1}; const ll mod=1e9+7; const ll N =400; const ll M =25000; const double eps = 1e-4; //const double pi=acos(-1); ll qk(ll a,ll b){ll ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b/=2;}return ans%mod;}int n,m; int d[N]; int sum[N]; namespace BO{int n;int dfn[M];int low[N], fa[N];int tim;int pre[N];int match[N];queue<int>q;int h[N], to[M], nex[M], idx;int vis[N];int ans;void add(int x, int y,int o){to[idx] = y;nex[idx] = h[x];h[x] = idx ++ ;if(o) add(y,x,0);}int Find(int x){if(fa[x] == x)return x;return fa[x] = Find(fa[x]);}//樸素的lca,根據(jù)建圖的方式暴力跳int lca(int x, int y){++ tim;//時(shí)間戳 / 縮點(diǎn)的編號(hào)while(dfn[x] != tim){dfn[x] = tim;//每走一步就標(biāo)記一下, 如果遇見一個(gè)點(diǎn)已經(jīng)被標(biāo)記過了就說明這個(gè)點(diǎn)已經(jīng)被另一個(gè)點(diǎn)走過了,也就說明是lcax = Find(pre[match[x]]);if(y)swap(x, y);}return x;}//開花(縮環(huán)) //x和y是要開花的兩個(gè)點(diǎn)(此時(shí)x和y都是黑點(diǎn)剛找到奇環(huán)的時(shí)候) //w是他們的lca //整個(gè)花縮完之后就是一個(gè)黑點(diǎn)// !這里雖然是兩個(gè)點(diǎn)但是只是從x走到了x和y的lca:w,y到w路徑上的點(diǎn)并沒有染色或者丟到隊(duì)列里去,所以要開兩次,一次x一次y。void blossom(int x, int y, int w){while(Find(x) != w){pre[x] = y;y = match[x];//如果是白點(diǎn)就直接染成黑色,然后丟到隊(duì)列里面vis[y] = 1, q.push(y);if(Find(x) == x) fa[x] = w;if(Find(y) == y) fa[y] = w;x = pre[y];}}int aug(int s){if((ans + 1) * 2 > n)return 0;for(int i = 1; i <= n; ++ i)fa[i] = i, pre[i] = vis[i] = 0;while(!q.empty()) q.pop();q.push(s);vis[s] = 1;//從黑點(diǎn)開始//隊(duì)列中都是黑點(diǎn),所以遇到相鄰未染色的點(diǎn)都染成白點(diǎn)while(!q.empty()){int x = q.front();q.pop();for(int i = h[x] ; ~i; i = nex[i]){int y = to[i];//如果相鄰點(diǎn)是白點(diǎn),或者是同一朵花中的節(jié)點(diǎn),則直接跳過這個(gè)點(diǎn)if(Find(x) == Find(y) || vis[y] == 2)continue;if(!vis[y]) { //未染色(匹配)點(diǎn),說明找到了增廣路vis[y] = 2;//沒染色就把它染成白色pre[y] = x;if(!match[y]){int u = y;while(u){int v = pre[u], z = match[v];match[u] = v;match[v] = u;u = z;}return 1;}vis[match[y]] = 1, q.push(match[y]);}else{int w = lca(x, y);blossom(x, y, w);blossom(y, x, w);}}}return 0;}inline void main(int _n){n=_n;for(int i=1;i<=n;i++)if(!match[i]) ans+=aug(i);}inline void init(){memset(match, 0, sizeof match);memset(h,-1,sizeof(h));memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));tim=0;idx=0;ans=0;} } void sovle(){while(cin>>n>>m){int deg=0;for(int i=1;i<=n;i++) {cin>>d[i];deg+=d[i];sum[i]=sum[i-1]+d[i-1];}BO::init();int cnt=sum[n]+d[n];for(int i=1;i<=m;i++){int u,v;cin>>u>>v;BO::add(cnt+1,cnt+2,1);//拆邊f(xié)or(int j=1;j<=d[u];j++) BO::add(cnt+1,sum[u]+j,1);for(int j=1;j<=d[v];j++) BO::add(cnt+2,sum[v]+j,1);cnt+=2;}BO::main(cnt);int k=BO::ans;// cout<<cnt<<" "<<k<<endl;if((deg)%2==0&&k*2==cnt) cout<<"Yes\n";else cout<<"No\n";} } int main() { #ifdef LOCALfreopen("in.txt", "r", stdin); #elseiosint t=1;//cin>>t;while(t--) sovle(); #endif // LOCALreturn 0; }參考:大神題解
總結(jié)
以上是生活随笔為你收集整理的2020牛客多校第1场I-1 or 2一般图最大匹配带花树的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果的WWDC背后有什么深意?
- 下一篇: HDU.6761.Minimum Ind