poj 2831 次小生成树

给你一幅图,再给你Q个询问

每个询问为id c

即如果将id这条边的边权改为c的话,这条边是否可能是最小生成树中的一条边

做法:先对原图做一次最小生成树,顺便记录一下树中点对间的最长树边是多少

如果id的边权c小于两点间最长的树边,则肯定可以去掉路径上的一条边使得最小生成树总权值更小

View Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf = ~0u>>2;
const int maxn = 1010;
bool flag[maxn];
int D[maxn];
int n,map[maxn][maxn];
int mx[maxn][maxn],pre[maxn];
int prime(){
    memset(mx,0,sizeof(mx));
    int v,ret=0,mi;
    for(int i=1;i<=n;i++){
        flag[i]=0;  D[i]=inf;
    }D[1]=0;flag[1]=1;v=1;
    for(int k=1;k<n;k++){
        for(int i=1;i<=n;i++)if(!flag[i]){
            if(map[v][i]<D[i])
                D[i]=map[v][i],pre[i]=v;
        } mi=inf;
        for(int i=1;i<=n;i++)
            if(!flag[i]&&D[i]<mi)  mi=D[v=i];
        for(int i=1;i<=n;i++) if(flag[i]){
            mx[v][i]=max(mx[i][pre[v]],D[v]);
            mx[i][v]=mx[v][i];
        }
        flag[v]=1; ret+=mi;
    }
    return ret;
}
struct Edge{
    int s,t,c;
    Edge(){}
    Edge(int ss,int tt,int cc):s(ss),t(tt),c(cc){}
}edge[maxn*maxn];
int main(){
    int m,q,a,b,c,id,num;
    while(scanf("%d%d%d",&n,&m,&q)!=EOF){
        for(int i=1;i<=n;i++){
            map[i][i]=0;
            for(int j=i+1;j<=n;j++){
                map[i][j]=map[j][i]=inf;
            }
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&c);
            edge[i]=Edge(a,b,c);
            map[b][a]=map[a][b]=min(map[a][b],c);
        }
        prime();
        while(q--){
            scanf("%d%d",&id,&num);
            printf("%s\n",mx[edge[id].s][edge[id].t]>=num?"Yes":"No");
        }
    }
    return 0;
}
posted @ 2012-07-06 21:31  Because Of You  Views(889)  Comments(0Edit  收藏  举报