LightOJ 1251 Stream My Contest (minimal tree)

Minimum tree

Personal understanding is required to specify the starting point of the minimum spanning tree of a directed graph.

Probably steps of the algorithm is as follows:

  1. Traversing all edges, obtained from step to reach the point in v [v] and the precursor pre [v]. (Except the root node, if any, may not be reaching the point of no solution)
  2. Through all the points v, ans + in [v] (v equivalent walked away from the nearest point v), to see whether the ring (has been running pre, he can go to the instructions on the ring), if in ring points on the upper ring will shrink to a new point id [cnt ++]
  3. If a ring has not been found, the smallest tree constructed, return ans
  4. Otherwise, all single points are also constructed a new point id [cnt ++], right to the edge of the update number and edge points, if not in a point at both ends of the side edge weights to be subtracted in [v] (2 ans have been added in in [v], and the matter went to that edge from v, have gone in [v], as to a new point in time, understood as a personal ring has been shrunk to a point, on the edge of the ring has not leavin)

LightOJ 1384

Unicom network build cost is minimal tree, half the minimum bandwidth and then re-built map, run the smallest tree is less than the maximum cost.


#include<bits/stdc++.h>
#define ll long long
#define ls(r)   r<<1
#define rs(r)   r<<1|1
using namespace std;
const int N = 1e3+10;
const int INF = 0x3f3f3f3f;

struct edge{
    int u,v,w,cost;
    edge(int u,int v,int w,int cost):u(u),v(v),w(w),cost(cost){}
    edge(){}
};

struct directed_MT{
    int n,m;
    edge e[N*10];
    int vis[N],pre[N],id[N],in[N];  // 是否被访问过,前驱节点,新点编号,前驱到他的距离
    void init(int _n){n = _n; m = 0;}
    void add(int u,int v,int w){e[m++] = edge(u,v,w,0);}

    int dirMt(int sp){
        int ans = 0;
        while(1){
            for(int i=0;i<n;++i)    in[i] = INF;    // 初始化
            for(int i=0;i<m;++i){
                int u = e[i].u;
                int v = e[i].v;
                // 更新v的距离,和前驱
                if(e[i].w < in[v] && u!=v){
                    in[v] = e[i].w;
                    pre[v] = u;
                }                
            }
            for(int i=0;i<n;++i){
                if(i==sp) continue;
                // 无法到达 i 点 不连通
                if(in[i] == INF)    return -1;
            }
            int cnt = 0;    // 新图点的数量
            memset(id,-1,sizeof id);
            memset(vis,-1,sizeof vis);
            in[sp] = 0; // 初始点不要钱
            for(int i=0;i<n;++i){
                ans += in[i];   // 加上到这个点的距离
                int v = i;
                // 找自环
                while(vis[v]!=i && id[v]==-1 && v!=sp){
                    vis[v] = i;
                    v = pre[v];
                }
                if(v!=sp && id[v] ==-1){    // 缩点
                    for(int u=pre[v];u!=v;u=pre[u]) 
                        id[u] = cnt;
                    id[v] = cnt++;
                }
            }
// cerr << cnt << ' ' ;
            if(cnt==0)  break;  // 没有自环 算法截止
            for(int i=0;i<n;++i)    // 一个点构成一个环
                if(id[i]==-1)   id[i] = cnt++;
            for(int i=0;i<m;++i){  // 重新构图
                int v = e[i].v;
                e[i].v = id[e[i].v];
                e[i].u = id[e[i].u];
                if(e[i].v != e[i].u)    // 加不加貌似无所谓
                    e[i].w -= in[v];    // 已经可以到达v,所以到v的距离要减去
            }
            n = cnt;
            sp = id[sp];    // 更新节点个数和根节点
        }
        return ans;
    }
}MT;
edge e[N*10];
int n,m,c;
int check(int k){
    MT.init(n);
    for(int i=1;i<=m;++i){
        if(e[i].cost>=k)   MT.add(e[i].u,e[i].v,e[i].w);
    }
    int res =  MT.dirMt(0);
    return res <= c && res!=-1;
}

void solve(){
    scanf("%d%d%d",&n,&m,&c);
    MT.init(n);
    int u,v,w,cost;
    for(int i=1;i<=m;++i){
        scanf("%d%d%d%d",&u,&v,&w,&cost);
        e[i] = edge(u,v,cost,w);
    }
    int l=0,r=1e6+10;
    int mid,ans = -1;
    while(l<=r){
        mid = (l+r)>>1;
        if(check(mid)){
            ans = mid;
            l = mid + 1;
        }else{
            r = mid - 1;
        }
    }
    if(ans <= 0)   puts("impossible");
    else  printf("%d kbps\n",ans);
}
int main(){
    // freopen("1.out","w",stdout);
    int t; scanf("%d",&t);
    for(int i=1;i<=t;++i){
        printf("Case %d: ",i);
        solve();
    }
    return 0;
}

Learning blog

Guess you like

Origin www.cnblogs.com/xxrlz/p/11627511.html