HDU 5483(Nux Walpurgis-一定在MST中的边)

给定一张 n3000  的完全无向图,已知边权,求一定在MST上的边的边数

先求出MST,
然后令 f[roo][i]  表示以roo为根,是否存在一条非树边 (roo,v)  其与树链
(roo,x)  构成环 (rooxvroo) 

然后对于一条边 (x,v)  ,然后让v的子树作根,连接到x以下的节点去。

#include<bits/stdc++.h>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair 
#define MAXW (3000+10)
#define MAXN (3000+10)
#define MAXT (20+10)
#define MAXM (6000+10)
typedef long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int n,Map[MAXN][MAXN]={0};

int edge[MAXM],Next[MAXM],Pre[MAXM],siz=1;
void addedge(int u,int v) {
    edge[++siz]=v;
    Next[siz]=Pre[u];
    Pre[u]=siz;
}
void addedge2(int u,int v) {addedge(u,v),addedge(v,u);} 
int dis[MAXN],vis[MAXN],pree[MAXN];
int prim()
{   
    int mst=0;
    MEM(Pre) siz=1;
    MEM(vis)
    dis[1]=0; vis[1]=1; 
    Fork(i,2,n)
    {
         dis[i]=Map[1][i];
         pree[i]=1;
    }
    dis[0]=INF;
    For(j,n-1) {
        int k=0;
        For(i,n) if (!vis[i] && dis[k] > dis[i] ) k = i;

        addedge2(pree[k],k);
        mst+=dis[k];
        vis[k]=1; dis[k]=0;
        For(i,n) {
            if (!vis[i] && dis[i] > Map[k][i] ) {
                dis[i]=Map[k][i]; pree[i]=k;
            } 
        }

    }
    return mst;

} 

int f[MAXN][MAXN],roo;
void dfs(int x,int fa){
    if ( x == roo || fa == roo ) f[roo][x] = INF; 
    else f[roo][x]=Map[roo][x];
    Forp(x) {
        int v=edge[p];
        if (fa==v) continue;
        dfs(v,x); 
        f[roo][x]=min(f[roo][x],f[roo][v]);
    }

}
int dfs2(int x,int fa,int y) {
    int ans=f[x][y];
    Forp(x) {
        int v=edge[p];
        if (fa==v) continue;
        ans=min(ans,dfs2(v,x,y)); 
    }
    return ans;
}

void calc() {
    int ans=n-1;
    For(x,n) {
        Forp(x) 
        {
            int v=edge[p];
            if (x>=v) continue;

            if (dfs2(x,v,v)==Map[x][v]) 
            {
                ans--;
            }
        }
    }
    cout<<ans<<endl;
}

int main()
{
//  freopen("hdu5483.in","r",stdin);
//  freopen(".out","w",stdout);

    int T;cin>>T;
    while (T--) {

        cin>>n;
        For(i,n-1)
        {
            Fork(j,i+1,n) {
                scanf("%d",&Map[i][j]);
                Map[j][i]=Map[i][j];
            }
        }   

        int mst=prim();

        For(i,n) f[i][i]=0;
        For(i,n) roo=i,dfs(i,0); 

        calc();



    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值