借鉴了一位大佬的思路:https://blog.csdn.net/a670531899/article/details/81515505
题意:
一个有向图,要你去掉其中的一条边,使得剩下的两个图是不连通的,同时满足两个图权值差的绝对值最小。
思路:
因为砍掉边之后剩下的两个图不连通,所以砍掉的边肯定是桥,于是通过tarjan求出所有的桥,将图缩成树之后,遍历每个桥,求出桥两边两个子树差的绝对值的最小值。
至于求子树的权值,明显用到树形dp,树的总权值减去 两倍的子树权值即为两个子树权值的差。
代码:
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <stack>
using namespace std;
const int maxn =30000+10;
vector<int> G[maxn];
stack<int> S;
int N,M,k,ans;
int w[maxn],pre[maxn],low[maxn],sccno[maxn],dfs_clock,scc_cnt;
int sum,num[maxn];
int head[maxn],vis[maxn],dp[maxn];
struct Edge
{
int v,next,flag;
Edge(){};
Edge(int v1,int next1,int flag1)
{
v=v1,next=next1,flag=flag1;
}
}e[maxn*3];
void add_edge(int u,int v)
{
e[k]=Edge(v,head[u],0);
head[u]=k++;
}
void init()
{
for(int i=0; i<=N; i++)
G[i].clear();
k=sum=dfs_clock=scc_cnt=0;
memset(head,-1,sizeof(head));
memset(sccno,0,sizeof(sccno));
memset(pre,0,sizeof(pre));
memset(num,0,sizeof(num));
memset(dp,0,sizeof(dp));
}
void tarjan(int u)
{
pre[u] = low[u] = ++dfs_clock;
S.push(u);
for(int i=head[u]; i!=-1; i=e[i].next)
{
int v = e[i].v;
if(e[i].flag)
continue;
e[i].flag=e[i^1].flag=1;
if(!pre[v])
{
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(!sccno[v])
{
low[u] = min(low[u],pre[v]);
}
}
if(low[u]==pre[u])
{
scc_cnt++;
for(;;)
{
int x = S.top();
S.pop();
sccno[x] = scc_cnt;
num[scc_cnt]+=w[x];
if(x==u)
break;
}
}
}
void dfs(int u)
{
vis[u]=1;
dp[u]=num[u];
for(int i=0; i<G[u].size(); i++)
{
int v=G[u][i];
if(vis[v])
continue;
dfs(v);
dp[u]+=dp[v];
}
ans=min(ans,abs(sum-2*dp[u]));
}
int main()
{
while(scanf("%d %d",&N,&M)!=EOF)
{
init();
for(int i=0; i<N; i++)
{
scanf("%d",&w[i]);
sum+=w[i];
}
int a,b;
for(int i=1; i<=M; i++)
{
scanf("%d %d",&a,&b);
add_edge(a,b);
add_edge(b,a);
}
tarjan(0);
if(scc_cnt==1)
{
printf("impossible\n");
continue;
}
for(int i=0; i<N; i++)
{
for(int j=head[i]; j!=-1; j=e[j].next)
{
int v=e[j].v;
if(sccno[i]!=sccno[v])
{
G[sccno[i]].push_back(sccno[v]);
G[sccno[v]].push_back(sccno[i]);
}
}
}
ans=0x3f3f3f3f;
memset(vis,0,sizeof(vis));
dfs(1);
printf("%d\n",ans);
}
return 0;
}