CCF 201604-5(10分代码)

CCF 201604-5(10分代码)

代码量大,得分不高,没有什么参考价值。
整体思路是,最小生成树,最后去除不必要点。

#include<algorithm>
#include <vector>
#include <iostream>
using namespace std;
#define INF 3000

long long ans=0;
struct Edge		//边的结构体
{
    int a,b,cost;		//(a,b)边的权cost
}edge[100000+100];		//边的集合,等会用于排序
int parent[500+5];		//并查集,将每个联通分量都用最上方的根表示

struct Node{
    bool flag=false;
    int num=0,l=0,poi=0;
    int next[550],cost[550];
}node[550];

bool com(Edge a,Edge b)
{
    return a.cost<b.cost;
}

void init()		//初始化parent数组
{
    for(int i=0;i<=500+5;i++)
    {
        node[i].poi=0;
        node[i].flag=false;
        parent[i]=i;
    }
}
int find(int x)
{
    int r=x;
    while(r!=parent[r])   //寻找根结点
        r=parent[r];
    int i=x,j;  		//i是最底层,j是从i往根处爬,
    while(i!=r) 		//压缩路径  将i结点直接连着根,j为i结点之前的父亲
    {
        j=parent[i];  	//j为i结点之前的父亲
        parent[i]=r;
        i=j;  		//重新对i结点(此时为前一个i结点的父亲) 做压缩路劲
    }  				//最终所有的结点都有共同的父亲,共同的根,一个根连着很多直系儿子
    return r;
}
int Union(int a,int b)		//连接两个连通分量 a和 b
{
    int x=find(a);
    int y=find(b);
    if(x!=y)			//如果a和b不是同一个连通分量则把其中一个联通分量的根认另一个联通分量的根为根(老大)
    {
        parent[x]=y;
        return 1;
    }
    return 0;
}

bool vis[550]={false};
bool DFS(int num){
    if(vis[num]) return false;
    vis[num]=true;
    bool res=false;
    for(int i=0;i<node[num].l;i++){
        int k=node[num].next[i],t;
        if(DFS(k)){
            res=true;
            ans+=node[num].cost[i];
        }
    }
    if(node[num].flag) res=true;
    vis[num]=false;
//    if(res) cout << node[num].num << endl;
    return res;
}

int main()
{
    int T,n,m,p,num;
    cin >> T;
    while(T--){
        init();
        cin >> n >> m >>p;
        getchar();
        for(int i=0;i<n;i++){
            char c;
            c=getchar();
            if(c=='1') node[i+1].flag=true,num=i+1;
        }
        for(int i=0;i<m;i++){
            int u,v,w;
            cin >> u >> v >> w;
            edge[i].a=u;
            edge[i].b=v;
            edge[i].cost=w;
        }
        sort(edge,edge+m,com);

        for(int i=0;i<m;i++)
        {
            int beg=edge[i].a,end=edge[i].b;
//            cout << beg << ' ' <<end << endl;
            if(Union(beg,end))		//如果边的两个顶点不是同一个连通分量则为我们选定的边
            {
//                cout << beg << ' ' << end << endl;
                node[beg].next[node[beg].poi]=end;
                node[end].next[node[end].poi]=beg;
                node[beg].cost[node[beg].poi]=edge[i].cost;
                node[end].cost[node[end].poi]=edge[i].cost;
                node[end].poi++;
                node[beg].poi++;
            }
        }


        for(int i=0;i<=n;i++){
            node[i].num=i;
            node[i].l=node[i].poi;
        }
//        cout << num << endl;
        DFS(num);
        cout <<ans << endl;
        ans=0;
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值