1. 程式人生 > >hdu3551 Hard Problem 【一般圖匹配】

hdu3551 Hard Problem 【一般圖匹配】

題意:給定一個無向圖,(可能重邊)問能否通過刪邊,得到每個點的度數(d)為給定的度數(D)。

分析:我們先不管邊上的兩點是哪個,只考慮這兩點的度數,現在刪掉某條邊,這邊上的兩點的度數都不為零那麼就可以刪,

這樣我們可以把這兩個“度”匹配,如果所有的匹配可,那麼所有多餘的都可以刪掉了。我們這樣將所有的點拆成它度數個點,

這樣我們就可以用帶花樹開花取求。建邊的時候不需要把兩邊上的所有點建邊,這樣會有很多邊重複,我們可以建立一箇中間邊,

使得這兩坨點間接相鄰。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 810
#define Mm 200005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
struct edge {
    int v,next;
}e[Mm];
int tot,head[Mn];
void addedge(int u,int v) {
    e[tot].v=v;
    e[tot].next=head[u];
    head[u]=tot++;
}
int cnt,pre[Mn];
int findpre(int x) {
    return x==pre[x]?pre[x]:pre[x]=findpre(pre[pre[x]]);
}
void ol(int a,int b) {
    a=findpre(a);
    b=findpre(b);
    if(a!=b) pre[a]=b;
}
int lk[Mn],vis[Mn],mark[Mn],match[Mn],ne[Mn];
int lca(int x,int y) {
    static int t=0;t++;
    while(1) {
        if(x!=-1) {
            x=findpre(x);
            if(vis[x]==t) return x;
            vis[x]=t;
            if(match[x]!=-1) x=ne[match[x]];
            else x=-1;
        }
        swap(x,y);
    }

}
queue<int> q;
void group(int a,int p) {
    while(a!=p) {
        int b=match[a],c=ne[b];
        if(findpre(c)!=p) ne[c]=b;
        if(mark[b]==2) mark[b]=1,q.push(b);
        if(mark[c]==2) mark[c]=1,q.push(c);
        ol(a,b),ol(b,c);
        a=c;
    }
}
void aug(int s) {
    for(int i=0;i<=cnt;i++) {
        ne[i]=-1;
        pre[i]=i;
        mark[i]=0;
        vis[i]=-1;
    }
    mark[s]=1;
    while(!q.empty()) q.pop();
    q.push(s);
    while((!q.empty())&&match[s]==-1) {
        int u=q.front();
        q.pop();
        for(int i=head[u];~i;i=e[i].next) {
            int v=e[i].v;
            if(match[u]==v||findpre(u)==findpre(v)||mark[v]==2) continue;
            if(mark[v]==1) {
                int r=lca(u,v);
                if(findpre(u)!=r) ne[u]=v;
                if(findpre(v)!=r) ne[v]=u;
                group(u,r);
                group(v,r);
            } else if(match[v]==-1) {
                ne[v]=u;
                for(int x=v;~x;) {
                    int y=ne[x];
                    int mv=match[y];
                    match[x]=y,match[y]=x;
                    x=mv;
                }
                break;
            } else {
                ne[v]=u;
                q.push(match[v]);
                mark[match[v]]=1;
                mark[v]=2;
            }
        }
    }
}
int degree[Mn];
int d[Mn];
int U[Mn],V[Mn];
int id[Mn],num[Mn];
void init() {
    tot=0;cnt=1;
    CLR(head,-1);
    CLR(id,0);
    CLR(degree,0);
}
void build(int n,int m) {
    for(int i=1;i<=m;i++) {
        int u=U[i],v=V[i];
        if(!id[u]) {
            id[u]=cnt;
            num[u]=cnt+d[u]-1;
            cnt+=d[u];
        }
        if(!id[v]) {
            id[v]=cnt;
            num[v]=cnt+d[v]-1;
            cnt+=d[v];
        }
        if(!id[n+i+1]) {
            id[n+i+1]=cnt;
            num[n+i+1]=cnt+1;
            cnt+=2;
        }
        int t=id[n+i+1];
        addedge(t,t+1);
        addedge(t+1,t);
        for(int j=id[u];j<=num[u];j++)
            addedge(t,j),addedge(j,t);
        for(int j=id[v];j<=num[v];j++)
            addedge(t+1,j),addedge(j,t+1);
    }
}
int main() {
    int t;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++) {
        int n,m;init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) {
            scanf("%d%d",&U[i],&V[i]);
            degree[U[i]]++;
            degree[V[i]]++;
        }
        int flag=1;
        for(int i=1;i<=n;i++) {
            scanf("%d",&d[i]);
            if(degree[i]<d[i]) flag=0;
            else d[i]=degree[i]-d[i];
        }
        printf("Case %d: ",cas);
        if(!flag) {
            printf("NO\n");
            continue;
        }
        build(n,m);
        int ans=0;
        cnt--;
        //cout<<cnt<<endl;
        for(int i=1;i<=cnt;i++) {
            match[i]=-1;
        }
        for(int i=1;i<=cnt;i++) {
            if(match[i]==-1) aug(i);
        }
        for(int i=1;i<=cnt;i++) {
            if(match[i]!=-1) ans++;
        }
        if(ans==cnt) {
            printf("YES\n");
        } else {
            printf("NO\n");
        }
    }
    return 0;
}


相關推薦

hdu3551 Hard Problem 一般匹配

題意:給定一個無向圖,(可能重邊)問能否通過刪邊,得到每個點的度數(d)為給定的度數(D)。 分析:我們先不管邊上的兩點是哪個,只考慮這兩點的度數,現在刪掉某條邊,這邊上的兩點的度數都不為零那麼就可以刪, 這樣我們可以把這兩個“度”匹配,如果所有的匹配可,那麼所有多餘的都

最短路二分匹配樹形背包DPDay 10.8

void second eof 最小 span har mes find names T1 最短路 1 #include <cstdio> 2 #include <queue> 3 #include <iostream>

hdu 1045 Fire Net 二分匹配

進行 col numbers res clu 意思 archive 多少 color <題目鏈接> <轉載於 >>> > 題目大意: 這題意思是給出一張圖,圖中‘X‘表示wall,‘.‘表示空地,可以放置炮臺,同一條直線上只

HDU 3829 Cat VS Dog (最大獨立集)二分匹配

<題目連結> 題目大意: 動物園有n條狗。m頭貓。p個小孩,每一個小孩有一個喜歡的動物和討厭的動物。如今動物園要轉移一些動物。假設一個小孩喜歡的動物在,不喜歡的動物不在,他就會happy。問動物最多能使幾個小孩happy。 解題分析: 因為本題不同的小孩之間喜好可能會產生衝突,所以,要使最

二分匹配HDU

題意: 給出一張圖,‘X’代表牆,‘.’ 代表空地。在空地上放一些炮塔,炮塔不能處在同一行同一列,除非被牆隔開。問最多能放多少個炮塔。 題解: 這題其實可以二進位制暴力模擬去做,但也可以用二分

過山車 二分匹配

## **題目描述**: RPG girls今天和大家一起去遊樂場玩,終於可以坐上夢寐以求的過山車了。可是,過山車的每一排只有兩個座位,而且還有條不成文的規矩,就是每個女生必須找個個男生做partn

二分匹配 最小點覆蓋==最大匹配

 先說一下,什麼叫做最小覆蓋點。     在一個二分圖中,一個x部或y部的覆蓋點可以覆蓋與之相連的所有線段,選擇一些點,使得覆蓋所有線段,點數最少。     König定理:最小覆蓋點數==最大匹配數     我有兩個證明。 **********************

LOJ2276 [HAOI2017] 新型城市化 二分匹配tarjan

分析 stack add 節點 題目 style bits 連通 發現 題目分析: 這題出的好! 首先問題肯定是二分圖的最大獨立集,如果刪去某條匹配邊之後獨立集是否會變大。 跑出最大流之後流滿的邊就是匹配邊。 如果一個匹配邊的兩個端點在一個強連通分量裏,那這條邊刪掉

二分匹配入門專題1E - Air Raid hdu1151最小路徑覆蓋

eno rate ask return red size all file 痛苦 Consider a town where all the streets are one-way and each street leads from one intersection to

二分匹配入門專題1F - COURSES poj1469最大匹配--匈牙利算法模板題

nbsp possible count dfs positive owin not hat first Consider a group of N students and P courses. Each student visits zero, one or more t

二分匹配入門專題1D - Matrix hdu2119最小頂點覆蓋

sample ins ever != sca either dfs ret int Give you a matrix(only contains 0 or 1),every time you can select a row or a column and delete

二分匹配入門專題1M - Cyclic Tour hdu1853km算法--判斷自重邊

初始化 case test case 思路 contain first rst ant eve There are N cities in our country, and M one-way roads connecting them. Now Little Tom wa

BZOJ2437 [Noi2011]兔兔與蛋蛋 博弈論 + 二分匹配

read cls www 判斷 ring get 必須 out AI 題目鏈接 BZOJ2437 題解 和JSOI2014很像 只不過這題動態刪點 如果我們把空位置看做\(X\)的話,就會發現我們走的路徑是一個\(OX\)交錯的路徑 然後將圖二分染色,當前點必勝,當且僅當當

二分匹配/匈牙利演算法飛行員配對方案問題

 P2756 飛行員配對方案問題 確認過眼神, 是二分圖匹配板子題啦!!! 跑個匈牙利, 有匹配的輸出, 記得先輸出外籍飛行員, 因為有spj順序無所謂啦qwq 最近A的最順利的題了哈哈哈哈哈哈開心!!!!!!!! 1 #include<cstdio> 2 #incl

HDU 1045 Fire Net 連通塊的壓縮 二分匹配

題目:http://acm.hdu.edu.cn/showproblem.php?pid=1045 Fire Net Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Jav

2018 BJTU Summer Training 二分匹配 & 網路流 & 費用流

前言(瞎BB) 網路流是我在OI生涯學的最後一個演算法,它很適合演算法競賽,因為它需要建立模型(圖)來反映題目中的限制條件,而且可以得出一些最優的東西(最大流),或者是搞出方案(搜尋殘量網路),這些都是演算法競賽最喜歡的。 高中就聽說過一位神犇,憑藉一手網路流解決了許多標

BZOJ 1854SCOI 2010遊戲並查集 & 二分匹配

Description lxhgww最近迷上了一款遊戲,在遊戲裡,他擁有很多的裝備,每種裝備都有2個屬性,這些屬性的值用[1,10000]之間的數表示。當他使用某種裝備時,他只能使用該裝備的某一個屬性。並且每種裝備最多隻能使用一次。 遊戲進行到最後,lxhgw

CodeForces 776D The Door Problem並查集

merge cnblogs 表示 turn pro name 所有 force mes CodeForces 776D The Door Problem【並查集】並查集 設 f 1--m 表示 開的情況 m+1--2*m 表示關的情況 對於每盞燈 如果他 是關

正則表達式範圍性匹配

bsp com pre www. find compile 轉義 什麽 sna 1、 import re key = r"<html><body><h1>hello world<h1></body></ht

計算幾何二分判定Gym - 101485C - Cleaning Pipes

你是 i+1 ace 機器 ble mes 方案 clu str 題意:有n個水井,每個水井發出一些管線(都是線段),然後每條管線上最多只有一個水井。所有從不同的水井發出的管線的相交點都是清潔點(不存在清潔點是大於兩條管線點的交點)。你需要在某些管線上放出一些機器人,它們會