HDU 4612 Warm up (边双连通分量+DP最长链)

题意】给定一个无向图,问在允许加一条边的情况下,最少的桥的个数 【 思路】对图做一遍Tarjan找出桥,把双连通分量缩成一个点,这样原图就成了一棵树,树的每条边都是桥。然后在树中求最长链,这样在两端点间连一条边就能形成环从而减少桥数。 不能更逗比。。多校第一场刚做出来的找最长链第二场就做错了= =,还一直以为是模板的问题。。。。。。  
#include 
 
   
    
  
#include 
  
    
      #include 
     
       #include 
      
        #include 
       
         #include 
        
          #define MID(x,y) ((x+y)/2) #define mem(a,b) memset(a,b,sizeof(a)) #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; const int MAXV = 200005; const int MAXE = 2000005; struct node{ int u, v; int next; bool bridge; }arc[MAXE]; int cnt, head[MAXV]; void init(){ cnt = 0; mem(head, -1); return ; } void add(int u, int v){ arc[cnt].u = u; arc[cnt].v = v; arc[cnt].next = head[u]; arc[cnt].bridge = false; head[u] = cnt ++; arc[cnt].u = v; arc[cnt].v = u; arc[cnt].next = head[v]; arc[cnt].bridge = false; head[v] = cnt ++; return ; } int id, dfn[MAXV], low[MAXV]; int bridge_num; bool vis_arc[MAXE]; //一条边无向边(两个有向边)只访问一次, void tarjan(int u){ dfn[u] = low[u] = ++ id; for (int i = head[u]; i != -1; i = arc[i].next){ if (vis_arc[i]) continue; int v = arc[i].v; vis_arc[i] = vis_arc[i^1] = 1; if (!dfn[v]){ tarjan(v); low[u] = min(low[u], low[v]); if (dfn[u] < low[v]){ arc[i].bridge = true; arc[i^1].bridge = true; bridge_num ++; } } else{ low[u] = min(low[u], dfn[v]); } } } int bcc_num; bool vis[MAXV]; int mark[MAXV]; //标记点属于哪个边双连通分支 vector 
         
           bcc[MAXV]; void fill(int u){ bcc[bcc_num].push_back(u); mark[u] = bcc_num; for (int i = head[u]; i != -1; i = arc[i].next){ if (arc[i].bridge) continue; int v = arc[i].v; if (mark[v] == 0) fill(v); } } void find_bcc(int n){ mem(vis, 0); mem(mark, 0); //确定每个点所属边双联通分量 for (int i = 1; i <= n; i ++){ if (mark[i] == 0){ ++ bcc_num; bcc[bcc_num].clear(); fill(i); } } return ; } void solve(int n){ id = bcc_num = bridge_num = 0; mem(dfn, 0); mem(low, 0); mem(vis_arc, 0); for (int i = 1; i <= n; i ++){ if (!dfn[i]) tarjan(i); } find_bcc(n); return ; } int maxlong; int dp[MAXV]; void long_list(int bccu, int n){ vis[bccu] = 1; int max1 =0, max2 = 0; int num = 0; for (int p = 0; p < (int)bcc[bccu].size(); p ++){ int u = bcc[bccu][p]; for (int i = head[u]; i != -1; i = arc[i].next){ if (arc[i].bridge){ int bccv = mark[arc[i].v]; if (!vis[bccv]){ num ++; long_list(bccv, n); if (dp[bccv] > max1){ max2 = max1; max1 = dp[bccv]; } else{ if (dp[bccv] > max2){ max2 = dp[bccv]; } } } } } } if (0 == num){ dp[bccu] = 0; } else{ if (num == 1) maxlong = max(maxlong, max1+1); else maxlong = max(maxlong, max1+max2+2); dp[bccu] = max1 + 1; } return ; } int n, m; int main(){ while(scanf("%d %d", &n, &m) != EOF){ if (n + m == 0) break; init(); for (int i = 0; i < m; i ++){ int u, v; scanf("%d %d", &u, &v); add(u, v); } solve(n); maxlong = 0; mem(dp, 0); mem(vis, 0); for (int i = 1; i <= bcc_num; i ++){ if (!vis[i]) long_list(i, n); } printf("%d\n", bridge_num - maxlong); } return 0; } 
          
         
        
       
      
    
 
   

你可能感兴趣的:(HDU)