1. 程式人生 > >HDOJ2242解題報告【邊雙連通分量】

HDOJ2242解題報告【邊雙連通分量】

algorithm signed min cst 所有 log ret fine str

題目地址:

  http://acm.hdu.edu.cn/showproblem.php?pid=2242

題目概述:

  中文題面就不贅述了。

大致思路:

  其實讀完題之後就知道是要求這張圖所有的橋,並且分別刪掉這些橋來更新答案。

  那麽就是求邊雙聯通分量了,求出來之後縮點,原圖變成一棵樹,然後在樹上維護這個點的子樹的權值和,然後枚舉樹上所有點來更新答案即可,詳見代碼。

復雜度分析:

  略。(才不是因為不會分析)

代碼:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include 
<cmath> #include <vector> #include <ctime> #include <map> #include <assert.h> #include <stack> #include <set> #include <queue> #include <cstring> #include <algorithm> using namespace std; #define sacnf scanf #define scnaf scanf #define pb push_back #define
Len size() #define maxn 10010 #define maxm 20010 #define inf 1061109567 //const long long inf=1e15; #define INF 0x3f3f3f3f #define Eps 0.000001 const double PI=acos(-1.0); #define mod 1000000007 #define MAXNUM 10000 #define For(i,j,k) for(int (i)=(j);(i)<=(k);(i)++) #define mes(a,b) memset((a),(b),sizeof(a)) #define scanfi(a) scanf("%d",&(a)) typedef
long long ll; typedef unsigned long long ulld; void Swap(int &a,int &b) {int t=a;a=b;b=t;} ll Abs(ll x) {return (x<0)?-x:x;} struct Edge { int from, to, next; } edge[maxm]; int head[maxn],edgenum; int low[maxn], dfn[maxn],dfs_clock; int ebcno[maxn], ebc_cnt; stack<int> S; bool Instack[maxn]; vector<int> ebc[maxn],G[maxn]; int total,ans; int num1[maxn],num2[maxn],d[maxn]; void addEdge(int u,int v) { edge[edgenum].from=u;edge[edgenum].to=v; edge[edgenum].next=head[u];head[u]=edgenum++; } void tarjan(int u,int fa) { int flag=0; low[u]=dfn[u]=++dfs_clock; S.push(u);Instack[u]=true; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(v==fa&&!flag) {flag=1;continue;} if(!dfn[v]) { tarjan(v,u); low[u]=min(low[u],low[v]); } else if(Instack[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { ebc_cnt++; ebc[ebc_cnt].clear(); for(;;) { int v=S.top();S.pop();Instack[v]=false; ebcno[v]=ebc_cnt;ebc[ebc_cnt].push_back(v); if(v==u) break; } } } void find_cut(int l, int r) { dfs_clock=ebc_cnt=0; mes(low,0);mes(dfn,0);mes(ebcno,0); mes(Instack,false); For(i,l,r) if(!dfn[i]) tarjan(i,-1); } void dfs(int u, int fa) { d[u]=num2[u];int len=G[u].Len; For(i,0,len-1) { int v=G[u][i]; if(v==fa) continue; dfs(v,u);d[u]+=d[v]; } ans=min(ans,abs(total-2*d[u])); } int main() { //freopen("data.in","r",stdin); //freopen("data.out","w",stdout); //clock_t st=clock(); int n,m; while(~scanf("%d%d",&n,&m)) { mes(head,-1);edgenum=0;total=0; For(i,1,n) scanfi(num1[i]),total+=num1[i]; int a,b; For(i,1,m) { scanf("%d%d", &a,&b);a++;b++; addEdge(a,b);addEdge(b,a); } find_cut(1,n); if(ebc_cnt==1) { printf("impossible\n"); continue; } For(i,1,ebc_cnt) { G[i].clear();int sum=0,len=ebc[i].Len; For(j,0,len-1) sum+=num1[ebc[i][j]]; num2[i]=sum; } for(int i=0;i<edgenum;i+=2) { int u=ebcno[edge[i].from]; int v=ebcno[edge[i].to]; if(u!=v) G[u].push_back(v),G[v].push_back(u); } ans=inf;dfs(1,-1); printf("%d\n",ans); } //clock_t ed=clock(); //printf("\n\nTime Used : %.5lf Ms.\n",(double)(ed-st)/CLOCKS_PER_SEC); return 0; }

HDOJ2242解題報告【邊雙連通分量】