hdu 1827 Summer Holiday

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

题目意思:在一棵有向图中,每个点都有一个权值,求有多少个连通分量;在某个连通分量中,求出可以遍历这个连通分量的点,使得这个点的权值最小。

思路:如果没有环,则起点就是所要求的点。如果有环且环上的点都能遍历这个边通分量,则选择环上权值最小的点。

定义:每次选择的初始点为根。

选择没有遍历过的点作为根,进行tarjan遍历,如果一开始就进入了环,则要把整个环都标记到根上,取环上的最小值作为根的权值。如果发现可以到达其它根,则把该根去掉。

View Code
#include<string.h>
#include<stdio.h>
#include<iostream>
#include<stack>
#include<stdlib.h>
#include<algorithm>
#include<utility>
using namespace std;
const int maxn = 1005;
struct nd
{
        int to,next;
}edge[maxn*4];
int ecnt,idx,cnt,tmp,ans;
int head[maxn],vis[maxn];
int dfn[maxn],low[maxn];
int as[maxn],bs[maxn],cs[maxn];
stack<int>st;

inline void add(int s,int t)
{
        edge[ecnt].to = t;
        edge[ecnt].next = head[s];
        head[s] = ecnt++;
}
void tarjan(int u,int fa)
{
        int i,v;
        dfn[u] = low[u] = ++idx;
        vis[u] = 1;
        st.push(u);
        for(i = head[u]; i != -1; i = edge[i].next){
                v = edge[i].to;
                if(dfn[v]==0){
                        tarjan(v,fa);
                        low[u] = min(low[v],low[u]);
                }else{
                        if(cs[v]||cs[bs[v]]){ cnt--; cs[v] = 0; cs[bs[v]] = 0; }//去掉根
                        if(vis[v]) low[u] = min(low[u],dfn[v]);
                }
        }
        if(low[u]==dfn[u]){
                do{
                        v = st.top();
                        st.pop();
                        vis[v] = 0;
                        if(u==fa){
                                bs[v] = u;//把整个环标记到根
                                tmp = min(tmp,as[v]);
                        }
                }while(v!=u);
        }
}
int main()
{
        int i,j,k,t,n,m,s;
        while(scanf("%d%d",&n,&m)==2)
        {
                memset(head,-1,sizeof(head));
                memset(vis,0,sizeof(vis));
                memset(bs,0,sizeof(bs));
                memset(dfn,0,sizeof(dfn));
                ecnt = 0; idx = 0;

                for(i = 1; i <= n; ++ i) scanf("%d",as+i);
                for(i = 0; i < m; ++ i)
                {
                        scanf("%d %d",&s,&t);
                        if(s!=t)
                        add(s,t);
                }
                ans = 0; cnt = 0;
                for(i = 1; i <= n; ++ i) if(!dfn[i]){
                        tmp = as[i];
                        tarjan(i,i);
                        if(bs[i]==i) cs[i] = tmp; else cs[i] = as[i];
                        cnt++;
                }
                for(i = 1; i <= n; ++ i){ ans += cs[i]; cs[i] = 0; }
                printf("%d %d\n",cnt,ans);
        }
        return 0;
}

 

posted on 2012-06-19 19:44  aigoruan  阅读(380)  评论(0)    收藏  举报

导航