考研路茫茫——空调教室
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1663 Accepted Submission(s): 486
Problem Description
众所周知,HDU的考研教室是没有空调的,于是就苦了不少不去图书馆的考研仔们。Lele也是其中一个。而某教室旁边又摆着两个未装上的空调,更是引起人们无限YY。
一个炎热的下午,Lele照例在教室睡觉的时候,竟然做起了空调教室的美梦。
Lele梦到学校某天终于大发慈悲给某个教室安上了一个空调。而且建造了了M条通气管道,让整个教学楼的全部教室都直接或间接和空调教室连通上,构成了教室群,于是,全部教室都能吹到空调了。
不仅仅这样,学校发现教室人数越来越多,单单一个空调已经不能满足大家的需求。于是,学校决定封闭掉一条通气管道,把全部教室分成两个连通的教室群,再在那个没有空调的教室群里添置一个空调。
当然,为了让效果更好,学校想让这两个教室群里的学生人数尽量平衡。于是学校找到了你,问你封闭哪条通气管道,使得两个教室群的人数尽量平衡,并且输出人数差值的绝对值。
一个炎热的下午,Lele照例在教室睡觉的时候,竟然做起了空调教室的美梦。
Lele梦到学校某天终于大发慈悲给某个教室安上了一个空调。而且建造了了M条通气管道,让整个教学楼的全部教室都直接或间接和空调教室连通上,构成了教室群,于是,全部教室都能吹到空调了。
不仅仅这样,学校发现教室人数越来越多,单单一个空调已经不能满足大家的需求。于是,学校决定封闭掉一条通气管道,把全部教室分成两个连通的教室群,再在那个没有空调的教室群里添置一个空调。
当然,为了让效果更好,学校想让这两个教室群里的学生人数尽量平衡。于是学校找到了你,问你封闭哪条通气管道,使得两个教室群的人数尽量平衡,并且输出人数差值的绝对值。
Input
本题目包含多组数据,请处理到文件结束。
每组测试第一行包含两个整数N和M(0<N<=10000,0<M<20000)。其中N表示教室的数目(教室编号从0到N-1),M表示通气管道的数目。
第二行有N个整数Vi(0<=Vi<=1000),分别代表每个教室的人数。
接下来有M行,每行两个整数Ai,Bi(0<=Ai,Bi<N),表示教室Ai和教室Bi之间建了一个通气管道。
每组测试第一行包含两个整数N和M(0<N<=10000,0<M<20000)。其中N表示教室的数目(教室编号从0到N-1),M表示通气管道的数目。
第二行有N个整数Vi(0<=Vi<=1000),分别代表每个教室的人数。
接下来有M行,每行两个整数Ai,Bi(0<=Ai,Bi<N),表示教室Ai和教室Bi之间建了一个通气管道。
Output
对于每组数据,请在一行里面输出所求的差值。
如果不管封闭哪条管道都不能把教室分成两个教室群,就输出"impossible"。
如果不管封闭哪条管道都不能把教室分成两个教室群,就输出"impossible"。
Sample Input
4 3 1 1 1 1 0 1 1 2 2 3 4 3 1 2 3 5 0 1 1 2 2 3
Sample Output
0 1思路:删除在环上的边显然不能使图不连通,所以要缩点,得到多个双连通分量,变成一棵树,删除的是树中的一条边,进行树dp即能求出答案。AC代码:#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <vector> #include <cmath> #include <map> #include <cstdlib> #define L(rt) (rt<<1) #define R(rt) (rt<<1|1) #define ll long long using namespace std; const int maxn=10005; const int maxm=20005; const int INF=1000000000; struct node { int v,next; }edge[maxm*4]; int G[maxn],NG[maxn],bcc[maxn],val[maxn],sum[maxn]; int low[maxn],dfn[maxn],stack[maxn]; bool ins[maxn],vis[maxn]; int n,m,num,tot,cnt,top,snum,ans; void init() { memset(G,-1,sizeof(G)); memset(NG,-1,sizeof(NG)); num=tot=0; } void add(int *head,int u,int v) { edge[num].v=v; edge[num].next=head[u]; head[u]=num++; } void input() { int a,b; for(int i=0;i<n;i++) { scanf("%d",&val[i]); tot+=val[i]; } while(m--) { scanf("%d%d",&a,&b); add(G,a,b); add(G,b,a); } } void dfs(int u,int pre) { int x; dfn[u]=low[u]=++cnt; stack[top++]=u; ins[u]=true; bool flag=true; for(int i=G[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v==pre&&flag) {flag=false; continue;} if(!dfn[v]) { dfs(v,u); low[u]=min(low[u],low[v]); if(low[v]>dfn[u]) //找到桥 { do{ x=stack[--top]; ins[x]=false; bcc[x]=snum; }while(x!=v); snum++; } } else if(ins[v]) low[u]=min(low[u],dfn[v]); } } void tarjan() { memset(dfn,0,sizeof(dfn)); memset(bcc,0,sizeof(bcc)); memset(ins,false,sizeof(ins)); cnt=top=0; snum=1; dfs(0,-1); } int treedp(int u) { int ret=sum[u]; vis[u]=true; for(int i=NG[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(vis[v]) continue; ret+=treedp(v); } if(ans>abs(tot-2*ret)) ans=abs(tot-2*ret); return ret; } void solve() { if(snum==1) { printf("impossible\n"); return; } memset(sum,0,sizeof(sum)); for(int i=0;i<n;i++) sum[bcc[i]]+=val[i]; for(int u=0;u<n;u++) for(int i=G[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(bcc[u]!=bcc[v]) add(NG,bcc[u],bcc[v]); } ans=INF; memset(vis,false,sizeof(vis)); treedp(0); printf("%d\n",ans); } int main() { while(~scanf("%d%d",&n,&m)) { init(); input(); tarjan(); solve(); } return 0; }