Codeforces 160D Edges in MST

最近发现,不写题解不长记性。

题意:给出一张带权无向图,然后询问该图的每条边进行询问,若这条边出现在该图的所有最小生成树中,输出any;若这条边可以出现在这张图的某几个最小生成树中,输出at least once;若这条边不会出现在这张图的任意一个最小生成树中,输出none。

解法:跟求最小生成树的方法类似,首先将所有边按照权值从小到大排序,一次取出所有边长相等的边,查询每条边的两个节点是否在同一集合中,若不在同一集合中,则在这两个集合间添加一条无向边,同时认为这些边有可能出现在该图的最小生成树中。再做tarjan找桥,找到桥将一定出现在该图的最小生成树中。然后将所有的边的两个端点合并到同一集合,在合并到同一集合的过程中,同时清除该在集合上的所有的边。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 100010
using namespace std;

struct Edge{
    int from,to,dist,id;
}a[maxn];

int first[maxn],v[maxn*2],next[maxn*2],id[maxn*2];
int ans[maxn],fa[maxn],pre[maxn],dfs_clock,e;

int cmp(Edge a,Edge b){
    return a.dist < b.dist;
}
void init(){
    e = 0;
    memset(first,-1,sizeof(first));
}

void add_edge(int a,int b,int ID){
    v[e] = b;
    next[e] = first[a];
    id[e] = ID;
    first[a] = e++;
}

int dfs(int u,int fa_id){
    int lowu = pre[u] = ++dfs_clock;
    for(int i = first[u];i != -1;i = next[i]){
        if(!pre[v[i]]){
            int lowv = dfs(v[i],id[i]);
            lowu = min(lowu,lowv);
            if(lowv > pre[u])   ans[id[i]] = 1;
        }else if(pre[v[i]] < pre[u] && id[i] != fa_id){
            lowu = min(lowu,pre[v[i]]);
        }
    }
    return lowu;
}

int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);}

void join(int x,int y){
    int fx = find(x);
    int fy = find(y);
    if(fx != fy){
        e = 0;
        first[fx] = first[fy] = -1;
        pre[fx] = pre[fy] = 0;
        fa[fx] = fy;
    }
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    init();
    for(int i = 1;i <= n;i++)   fa[i] = i;
    dfs_clock = 0;
    for(int i = 0;i < m;i++){
        scanf("%d%d%d",&a[i].from,&a[i].to,&a[i].dist);
        a[i].id = i;
    }
    sort(a,a+m,cmp);
    memset(pre,0,sizeof(pre));
    memset(ans,0,sizeof(ans));
    for(int i = 0;i < m;i++){
        int j = i+1;
        while(j < m && a[i].dist == a[j].dist)    j++;
        for(int k = i;k < j;k++){
            int fx = find(a[k].from);
            int fy = find(a[k].to);
            if(fx != fy){
                add_edge(fx,fy,a[k].id);
                add_edge(fy,fx,a[k].id);
                ans[a[k].id] = 2;
            }
        }
        for(int k = i;k < j;k++){
            int fx = find(a[k].from);
            int fy = find(a[k].to);
            if(fx != fy && !pre[fx]){
                dfs(fx,-1);
            }
        }
        for(int k = i;k < j;k++){
            join(a[k].from,a[k].to);
        }
        i = j - 1;
    }
    for(int i = 0;i < m;i++){
        if(ans[i] == 0) printf("none\n");
        else if(ans[i] == 1)    printf("any\n");
        else    printf("at least one\n");
    }
    return 0;
}
View Code

 

posted @ 2013-08-02 15:41  浙西贫农  阅读(587)  评论(0)    收藏  举报