zoukankan      html  css  js  c++  java
  • hdu2242 考研路茫茫——空调教室 (双连通)

    题意:给出一些点,有值,给出一些边,然后求去掉一条边后将分成连通的两部分,且两部分的差值最小

    分析:首先,求出所有的双连通分量,缩点,重新构图,再dfs (类似树形DP的过程)一遍就可以找出最小差值。但是,因为tarjan 算法的本质就是一个dfs,所有可以在求双连通分量的同时求出最小差值。

    注意:有重边的情况,因为人为的加了一条双向边,那个是无效的,但是原图的重边是有效的, 在这里WA 了N次

    View Code
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #define MAXN 10010
    using namespace std;
    int n,dfn[MAXN],low[MAXN],w[MAXN],index;
    int sub,sum,num;
    bool vis[MAXN];
    vector<int> g[MAXN];
    stack<int> st;
    void tarjan(int u,int p)
    {
    dfn[u]=low[u]=index++;
    vis[u]=true;
    st.push(u);
    int flag=1;//flag 用于排除人为加入的反向边,该边是无效的
    for(int i=0;i<g[u].size();i++)
    {
    int v=g[u][i];
    if(v==p && flag)
    {
    flag=0;
    continue;
    }
    if(!vis[v])
    {
    tarjan(v,u);
    low[u]=min(low[v],low[u]);
    if(dfn[u]<low[v])
    {
    int temp=0,x;
    do
    {
    x=st.top();
    temp+=w[x];
    st.pop();
    }while(x!=v);
    sub=min(sub,abs(sum-2*temp));
    w[u]+=temp;
    num++;
    }
    }
    else
    low[u]=min(low[u],dfn[v]);
    }
    }
    int main()
    {
    int m,a,b;
    while(scanf("%d %d",&n,&m)==2)
    {
    sum=0;
    for(int i=0;i<n;i++)
    {
    g[i].clear();
    scanf("%d",&w[i]);
    sum+=w[i];
    }
    while(m--)
    {
    scanf("%d %d",&a,&b);
    g[a].push_back(b);
    g[b].push_back(a);
    }
    index=num=0;
    memset(vis,false,sizeof(vis));
    sub=INT_MAX;
    while(!st.empty())
    st.pop();
    tarjan(0,-1);
    if(num==0)
    {
    printf("impossible\n");
    continue;
    }
    printf("%d\n",sub);
    }
    return 0;
    }
  • 相关阅读:
    单例模式
    iOS宏定义
    WKWebView基本使用
    文件操作(NSFileManager)
    iOS 字典和NSData之间转换
    iOS 身份证,邮箱,手机号验证
    iOS自定义数字键盘
    iOS指纹识别
    JavaScript表单
    JavaScript数组操作方法集合(2)
  • 原文地址:https://www.cnblogs.com/nanke/p/2367733.html
Copyright © 2011-2022 走看看