HDU2242 考研路茫茫——空调教室

10 篇文章 0 订阅
10 篇文章 0 订阅

传送门
Problem Description
众所周知,HDU的考研教室是没有空调的,于是就苦了不少不去图书馆的考研仔们。Lele也是其中一个。而某教室旁边又摆着两个未装上的空调,更是引起人们无限YY。

一个炎热的下午,Lele照例在教室睡觉的时候,竟然做起了空调教室的美梦。

Lele梦到学校某天终于大发慈悲给某个教室安上了一个空调。而且建造了了M条通气管道,让整个教学楼的全部教室都直接或间接和空调教室连通上,构成了教室群,于是,全部教室都能吹到空调了。

不仅仅这样,学校发现教室人数越来越多,单单一个空调已经不能满足大家的需求。于是,学校决定封闭掉一条通气管道,把全部教室分成两个连通的教室群,再在那个没有空调的教室群里添置一个空调。

当然,为了让效果更好,学校想让这两个教室群里的学生人数尽量平衡。于是学校找到了你,问你封闭哪条通气管道,使得两个教室群的人数尽量平衡,并且输出人数差值的绝对值。
Input
本题目包含多组数据,请处理到文件结束。
每组测试第一行包含两个整数N和M(0

题解

tarjan边双连通分量缩点+dfs(树形dp?)
tarjan的时候注意因为双连通分量是无向图(关键),所以当我们用邻接表的时候就要判断重边;重构图的时候,我用了并查集来判断两点间是否已经连边,去掉以后会TLE。

CODE:

#include<cstdio>
#include<cstring>
#include<cstdlib>
const int N=1e5+10;
const int M=2e5+10;
struct edge
{
    int nxt,to,id;
}a[M<<1];
struct Edge
{
    int nxt,to;
}e[M<<1];
int head[N],Head[N],dfn[N],low[N],block[N],size[N];
int s[N],top;
int stu[N],f[N];
bool instack[N];
int n,m,x,y,num,Num,tot,cnt,Time,ans,Total;
inline int min(const int &a,const int &b){return a<b?a:b;}
inline void add(int x,int y)
{
    a[++num].nxt=head[x],a[num].to=y,a[num].id=++cnt,head[x]=num;
    a[++num].nxt=head[y],a[num].to=x,a[num].id=cnt,head[y]=num;
}
inline void add2(int x,int y)
{
    e[++Num].nxt=Head[x],e[Num].to=y,Head[x]=Num;
    e[++Num].nxt=Head[y],e[Num].to=x,Head[y]=Num;
}
int find(int n)
{
    if(f[n]!=n) f[n]=find(f[n]);
    return f[n];
}
bool merge(int x,int y)
{
    x=find(x),y=find(y);
    if(x==y) return 0;
    return f[y]=x,1;
}
void dfs(int now,int fa)
{
    dfn[now]=low[now]=++Time;
    instack[now]=1;
    s[++top]=now;
    for(int i=head[now];i;i=a[i].nxt)
    if(a[i].id!=fa)
      if(!dfn[a[i].to])
      {
        dfs(a[i].to,a[i].id);
        low[now]=min(low[now],low[a[i].to]);
      }
      else low[now]=min(low[now],dfn[a[i].to]);
    else;
    if(dfn[now]==low[now])
    {
        tot++;
        int tmp;
        do tmp=s[top--],instack[tmp]=0,block[tmp]=tot,size[tot]+=stu[tmp];
        while(tmp!=now);
    }
}
void Dfs(int now,int fa)
{
    for(int i=Head[now];i;i=e[i].nxt)
      if(e[i].to!=fa)
      {
        Dfs(e[i].to,now);
        size[now]+=size[e[i].to];
      }
    ans=min(ans,abs((size[now]<<1)-Total));
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(dfn,0,sizeof(dfn));
        memset(head,0,sizeof(head));
        memset(Head,0,sizeof(Head));
        memset(size,0,sizeof(size));
        num=Num=tot=cnt=Time=Total=0;ans=1e9;
        for(int i=1;i<=n;i++)
          scanf("%d",&stu[i]),Total+=stu[i];
        for(int i=1;i<=m;i++)
          scanf("%d%d",&x,&y),add(x+1,y+1);
        dfs(1,0);
        if(tot==1){puts("impossible");continue;}
        for(int i=1;i<=tot;i++)
          f[i]=i;
        for(int j=1;j<=n;j++)
          for(int i=head[j];i;i=a[i].nxt)
            if(block[j]!=block[a[i].to]&&merge(block[j],block[a[i].to])) add2(block[j],block[a[i].to]);
        Dfs(1,0);
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值