题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2242
起初做这题想的是用强联通图去做,但似乎怎么去想都没有办法把图和强联通扯上关系,因为图中的所有边都是双向的,所以所有点都是一定存在于一个强联通图中。后来才发现这个应该是双联通问题(DCC),在一个双联通图中去掉任意一条边都不改变其联通性,所以我们就与强联通问题相似,把所有双联通分量缩点建立DAG图,再DFS搜索求解。
#include <stdio.h>
#include <string.h>
#include <stack>
#include <cstdlib>
#include <iostream>
using namespace std;
#define N 10005
#define M 20005
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++;
}
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);
}
}
int dfs(int u,int father)
{
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()
{
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;
}
本文介绍了解决双联通图问题的一种方法,通过使用Tarjan算法找到双联通分量并进行缩点,最终转化为DAG图上的DFS搜索求解最小权值分割问题。
414

被折叠的 条评论
为什么被折叠?



