Problem Description
众所周知,HDU的考研教室是没有空调的,于是就苦了不少不去图书馆的考研仔们。Lele也是其中一个。而某教室旁边又摆着两个未装上的空调,更是引起人们无限YY。
一个炎热的下午,Lele照例在教室睡觉的时候,竟然做起了空调教室的美梦。
Lele梦到学校某天终于大发慈悲给某个教室安上了一个空调。而且建造了了M条通气管道,让整个教学楼的全部教室都直接或间接和空调教室连通上,构成了教室群,于是,全部教室都能吹到空调了。
不仅仅这样,学校发现教室人数越来越多,单单一个空调已经不能满足大家的需求。于是,学校决定封闭掉一条通气管道,把全部教室分成两个连通的教室群,再在那个没有空调的教室群里添置一个空调。
当然,为了让效果更好,学校想让这两个教室群里的学生人数尽量平衡。于是学校找到了你,问你封闭哪条通气管道,使得两个教室群的人数尽量平衡,并且输出人数差值的绝对值。
Input
本题目包含多组数据,请处理到文件结束。
每组测试第一行包含两个整数N和M(0
Output
对于每组数据,请在一行里面输出所求的差值。
如果不管封闭哪条管道都不能把教室分成两个教室群,就输出”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
思路
我已经不想说了这道题我整了一晚上怕是可以退役了。。。
代码
WA
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<stack>
using namespace std;
const int N=30000+5;
const int inf=0x3f3f3f3f;
int n,m,peo[N],head[N],num,minn,every,headd[N];
int low[N],dfn[N],tim,cnt,bl[N],val[N],numm,visit[N];
stack<int> s;
struct edge
{
int u,v,w;
int next;
}ed[N*2],edd[N*2];
void build(int u,int v)
{
ed[++num].u=u;
ed[num].v=v;
ed[num].w=1;
ed[num].next=head[u];
head[u]=num;
}
void add(int u,int v)
{
edd[++numm].v=v;
edd[numm].u=u;
edd[numm].w=1;
edd[numm].next=headd[u];
headd[u]=numm;
}
void Tarjan(int u,int father)
{
dfn[u]=low[u]=tim++;
visit[u]=1;
s.push(u);
int flag=0;
for (int j=head[u];j!=-1;j=ed[j].next)
{
int v=ed[j].v;
if (v==father&&!flag) {flag=1;continue;}
if (!visit[v]) Tarjan(v,u);
low[u]=min(low[u],low[v]);
}
if (dfn[u]==low[u])
{
cnt++;
for (int now;now!=u;)
{
now=s.top();
s.pop();
bl[now]=cnt;
val[cnt]+=peo[now];
}
}
}
void suopoint()
{
num=0;
for (int i=1;i<=n;i++)
for (int j=head[i];j!=-1;j=ed[j].next)
{
int v=ed[j].v;
if (bl[i]!=bl[v])
{
add(bl[i],bl[v]);
// add(bl[v],bl[i]);
}
}
}
void suo()
{
for (int i=0;i<num;i++)
{
int u=ed[i].u,v=ed[i].v;
if (bl[u]!=bl[v]) add(u,v);
}
}
int getmin(int u,int father)
{
int sum;
sum=val[u];
for (int i=headd[u];i!=-1;i=edd[i].next)
{
int v=edd[i].v;
if (v==father) continue;
sum+=getmin(v,u);
}
minn=min(minn,abs(every-2*sum));
return sum;
}
void clear()
{
memset(head,-1,sizeof(head));
memset(headd,-1,sizeof(headd));
memset(peo,0,sizeof(peo));
memset(low,0,sizeof(low));
memset(visit,0,sizeof(visit));
memset(dfn,0,sizeof(dfn));
memset(val,0,sizeof(val));
memset(bl,0,sizeof(bl));
while(!s.empty()) s.pop();
num=-1;tim=0;cnt=0;minn=inf;every=0;numm=-1;
}
int main()
{
freopen ( "in.txt", "r", stdin ) ;
// freopen ( "out.txt", "w", stdout ) ;
while(scanf("%d%d",&n,&m)!=EOF)
{
clear();
for (int i=0;i<n;i++)
{
scanf("%d",&peo[i]);
every+=peo[i];
}
for (int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
build(u,v);
build(v,u);
}
// for (int i=0;i<=n;i++)
// if (!bl[i]) Tarjan(i,i);
Tarjan(0,0);
if (cnt==1) {printf("impossible\n");goto h;}
// suopoint();
suo();
getmin(1,0);
printf("%d\n",minn);
h:;
}
}
/*
4 3
1 1 1 1
0 1
1 2
2 3
4 3
1 2 3 5
0 1
1 2
2 3
3 3
2 1 1
0 1
1 0
1 2
5 6
1 1 1 1 1
0 4
0 1
1 3
1 2
2 4
2 3
2 2
1 1
1 2
2 1
4 5
1 2 3 4
0 1
1 2
2 0
1 0
1 3
4 3
1 2 3 5
0 1
1 2
2 3
4 3
1 1 1 1
0 1
1 2
2 3
*/
AC
# include<stdio.h>
# include<string.h>
# include<stack>
#include<cmath>
using namespace std;
# define N 100005
# define M 200005
struct node{
int from,to,next;
}edge[2*M],edge1[2*M];
int head[N],tol,n,m,cnt,dfn[N],low[N],visit[N],Belong[N],tol1,head1[N],val[N],val1[N],SUM,Min,count;
stack<int>S;
void add(int a,int b)
{
edge[tol].from=a;edge[tol].to=b;edge[tol].next=head[a];head[a]=tol++;
}
void add1(int a,int b)
{
edge1[tol1].from=a;edge1[tol1].to=b;edge1[tol1].next=head1[a];head1[a]=tol1++;
}
int min(int a,int b)
{
return a<b?a:b;
}
void tarjan(int u,int father)//tarjan找双连通分量并进行缩点
{
int j,v,flag;
dfn[u]=low[u]=cnt++;
visit[u]=1;
S.push(u);
flag=0;
for(j=head[u];j!=-1;j=edge[j].next)
{
v=edge[j].to;
if(v==father && !flag) {flag=1;continue;}//考虑重边的情况,相当重要!
if(!visit[v]) tarjan(v,u);
low[u]=min(low[u],low[v]);
}
if(dfn[u]==low[u])
{
count++;
do{
v=S.top();
S.pop();
Belong[v]=count;
val[count]+=val1[v];
}while(v!=u);
}//用栈的好处在于使双联通分量的标号连续,如果直接用low[u]来存u的双联通分量,双联通分量的标号不连续,之后再建图的时候不方便
}
int dfs(int u,int father)//树形DP求解最小差值
{
int j,v,sum;
sum=val[u];
for(j=head1[u];j!=-1;j=edge1[j].next)
{
v=edge1[j].to;
if(v==father) continue;
sum+=dfs(v,u);
}
Min=min(Min,abs(SUM-2*sum));
return sum;
}
int main()
{
freopen ( "in.txt", "r", stdin ) ;
freopen ( "out1.txt", "w", stdout ) ;
int i,a,b;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(head,-1,sizeof(head));
tol=cnt=0;
SUM=0;
for(i=0;i<n;i++)
{
scanf("%d",&val1[i]);
SUM+=val1[i];
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
memset(visit,0,sizeof(visit));
memset(val,0,sizeof(val));
count=0;//存双联通分量的个数
tarjan(0,0);
if(count==1) {printf("impossible\n");continue;}
tol1=0;
memset(head1,-1,sizeof(head1));
for(i=0;i<tol;i++)
{
a=edge[i].from;
b=edge[i].to;
if(Belong[a]!=Belong[b]) add1(Belong[a],Belong[b]);
}
Min=0xfffffff;
dfs(1,0);
printf("%d\n",Min);
}
return 0;
}