http://acm.hdu.edu.cn/showproblem.php?pid=3551

题意:给出一个图,还有一个子图的度数,求有没有办法通过删边使得原图的度数变成那个子图的度数?

思路:我们考虑把每个点拆成du[i]-d[i]个点,代表要删去的度数,然后对于每条边,我们建立两个点eu,ev,eu与ev连边,如果这条边连接了i,j两个点,那么所有的i的点向eu连边,所有的j向ev连边,如果有完美匹配(就是所有点都有匹配)那么有解。

至于为什么:如果eu和ev是匹配边,代表这条边不删,因为这条边的两侧,也就是连接的两个点都有其他的匹配了,那么这条边就不用删。

如果这条边不是匹配边,那么说明i和eu匹配了,j和ev匹配了,这条边代表删掉了,而i和j的度数也-1了

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
struct edge{
int u,v;
}e[];
int n,m,p[],q[];
int match[],newbase;
int inqueue[],inpath[],G[][],inblossom[],father[];
int du[],d[],c[],base[],start,finish,head,tail;
int read(){
int t=,f=;char ch=getchar();
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (''<=ch&&ch<=''){t=t*+ch-'';ch=getchar();}
return t*f;
}
int lca(int u,int v){
memset(inpath,,sizeof inpath);
while (){
u=base[u];
inpath[u]=;
if (!match[u]) break;
u=father[match[u]];
}
while (){
v=base[v];
if (inpath[v]) break;
v=father[match[v]];
}
return v;
}
void reset(int u){
while (u!=newbase){
int v=match[u];
inblossom[base[v]]=inblossom[base[u]]=;
u=father[v];
if (base[u]!=newbase) father[u]=v;
}
}
void blossomcontract(int u,int v){
newbase=lca(u,v);
memset(inblossom,,sizeof inblossom);
reset(u);
reset(v);
if (base[u]!=newbase) father[u]=v;
if (base[v]!=newbase) father[v]=u;
for (int i=;i<=n;i++)
if (inblossom[base[i]]){
base[i]=newbase;
if (!inqueue[i]) c[++tail]=i,inqueue[i]=;
}
}
void findaugmentingpath(){
memset(inqueue,,sizeof inqueue);
memset(father,,sizeof father);
for (int i=;i<=n;i++) base[i]=i;
head=;tail=;c[]=start;inqueue[start]=;
finish=;
while (head<=tail){
int u=c[head++];
for (int v=;v<=n;v++)
if (G[u][v]&&base[u]!=base[v]&&match[v]!=u){
if (v==start||(match[v]>)&&(father[match[v]]>)){
blossomcontract(u,v);
}else
if (father[v]==){
father[v]=u;
if (match[v]){
c[++tail]=match[v];inqueue[match[v]]=;
}else{
finish=v;
return;
}
}
}
}
}
void augmentpath(){
int u,v,w;
u=finish;
while (u>){
v=father[u];
w=match[v];
match[u]=v;
match[v]=u;
u=w;
}
}
bool solve(){
int res=;
memset(match,,sizeof match);
for (int i=;i<=n;i++)
if (!match[i]){
start=i;
findaugmentingpath();
if (finish) augmentpath(),res++;
}
for (int i=;i<=n;i++)
if (!match[i]) return ;
return ;
}
bool build(){
memset(G,,sizeof G);
int cnt=;
for (int i=;i<=n;i++)
if (du[i]>d[i]) return ;
memset(p,,sizeof p);
for (int i=;i<=m;i++){
if (!p[e[i].u]){
p[e[i].u]=++cnt;
q[e[i].u]=cnt+d[e[i].u]-du[e[i].u]-;
cnt=cnt+d[e[i].u]-du[e[i].u]-;
}
if (!p[e[i].v]){
p[e[i].v]=++cnt;
q[e[i].v]=cnt+d[e[i].v]-du[e[i].v]-;
cnt=cnt+d[e[i].v]-du[e[i].v]-;
}
int k=cnt+;cnt+=;
G[k][k-]=G[k-][k]=;
for (int j=p[e[i].u];j<=q[e[i].u];j++) G[j][k-]=G[k-][j]=;
for (int j=p[e[i].v];j<=q[e[i].v];j++) G[j][k]=G[k][j]=;
}
n=cnt;
return ;
}
int main(){
int Tcase=;
int T=read();
while (T--){
n=read();m=read();
printf("Case %d: ",++Tcase);
memset(d,,sizeof d);
for (int i=;i<=m;i++){
e[i].u=read();e[i].v=read();
d[e[i].u]++;d[e[i].v]++;
}
for (int i=;i<=n;i++) du[i]=read();
if (build()&&solve()){
printf("YES\n");
}else{
printf("NO\n");
}
}
return ;
}

HDU 3551 Hard Problem的更多相关文章

  1. HDU 3549 Flow Problem(最大流)

    HDU 3549 Flow Problem(最大流) Time Limit: 5000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/ ...

  2. hdu 5106 Bits Problem(数位dp)

    题目链接:hdu 5106 Bits Problem 题目大意:给定n和r,要求算出[0,r)之间全部n-onebit数的和. 解题思路:数位dp,一个ct表示个数,dp表示和,然后就剩下普通的数位d ...

  3. HDU 3374 String Problem (KMP+最大最小表示)

    HDU 3374 String Problem (KMP+最大最小表示) String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory ...

  4. hdu 5105 Math Problem(数学)

    pid=5105" target="_blank" style="">题目链接:hdu 5105 Math Problem 题目大意:给定a.b ...

  5. Hdu 5445 Food Problem (2015长春网络赛 ACM/ICPC Asia Regional Changchun Online)

    题目链接: Hdu  5445 Food Problem 题目描述: 有n种甜点,每种都有三个属性(能量,空间,数目),有m辆卡车,每种都有是三个属性(空间,花费,数目).问至少运输p能量的甜点,花费 ...

  6. 网络流 HDU 3549 Flow Problem

    网络流 HDU 3549 Flow Problem 题目:pid=3549">http://acm.hdu.edu.cn/showproblem.php?pid=3549 用增广路算法 ...

  7. HDU 1022 Train Problem I

    A - Train Problem I Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u ...

  8. HDU 3374 String Problem(KMP+最大/最小表示)

    String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  9. hdu 3549 Flow Problem

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=3549 Flow Problem Description Network flow is a well- ...

随机推荐

  1. Python进程、线程、协程详解

    进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配.任务的调度. ...

  2. 如何看懂Code128条形码

    条形码就是我们看到的商品上有的那些竖条条. 要不是项目上用到这个或许我一辈子也不会对那个感兴趣. 条形码其实是分成很多类的,虽然他们看起来都差不多…… 常见的条形码的码制被称为39码.128码.417 ...

  3. CodeForces 55D Beautiful numbers(数位dp)

    数位dp,三个状态,dp[i][j][k],i状态表示位数,j状态表示各个位上数的最小公倍数,k状态表示余数 其中j共有48种状态,最大的是2520,所以状态k最多有2520个状态. #include ...

  4. 给想上MIT的牛学生说几句

    [来信] 老师您好! 非常冒昧的来打搅您,仅仅是在学习上实在有些困惑才来向您求教一番. 我是计算机科学与技术的大一学生,我非常喜欢我自己的专业,可是学校里讲的东西太慢,太浅,所以我一般都是自学,我在自 ...

  5. [Ruby] Ruby Variable Scope

    Scope defines where in a program a variable is accessible. Ruby has four types of variable scope, lo ...

  6. cocos2d-x项目过程记录(Objective-C转C++)

    (原创作品,欢迎转载,注明出处,谢谢:http://www.cnblogs.com/binxindoudou/admin/EditPosts.aspx?postid=3179335) 1.单例模式中, ...

  7. codevs 1128 导弹拦截 (贪心)

    /* 题目大体意思是两套系统好多导弹 怎样分配使得两个系统所拦截的最大半径之和最小 贪心:把距离1系统最远的 让2拦截 记好距离 然后按照距离1由远到近排序 对于每一个导弹 如果这之前的都给2拦截 则 ...

  8. tomcat常用命令

    关闭./shutdown.sh 查看Tomcat是否以关闭 ps -ef|grep java *如果你想直接干掉Tomcat,你可以使用kill命令,直接杀死Tomcat进程 kill -9 7010 ...

  9. js正则表达式验证大全

    /判断输入内容是否为空    function IsNull(){        var str = document.getElementById('str').value.trim();      ...

  10. sql 学习笔记 p46

    交换行 update tab1 set c1=c2,c2=c1  .说明sql是临时表的存储,在查询出来的结果为决定前,可以随意操纵临时表中的列 update tab set c1=c1+(selec ...