F - Teen Girl Squad(朱刘算法)

F - Teen Girl Squad
题目主要是最小树形图, 用朱刘算法求解。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1005;
struct nede
{
    int u;
    int v;
    int cost;
} Edge[maxn*maxn];
int pre[maxn], visit[maxn], id[maxn];
double in[maxn];
int zhuliu(int root, int n, int m)
{
    double res = 0;
    int v;
    while(1)
    {
        for(int i=0; i<n; i++)//到达当前点的最小权值,先初始化
            in[i] = INF;
        for(int i=0; i<m; i++)//遍历每一个边
        {
            if(Edge[i].u!=Edge[i].v&&Edge[i].cost<in[Edge[i].v])//如果是一个边并且权值小于到达当前点的权值,更新
            {
                pre[Edge[i].v] = Edge[i].u;//pre记录前一个点,也就是从哪一点到达当前点
                in[Edge[i].v] = Edge[i].cost;//更新权值
            }
        }
        for(int i=0; i<n; i++)//遍历每一个节点
        {
            if(i!=root&&in[i]==INF)//如果当前点不是根节点,但入度值最小为INF,也就是没有任何边指向此点,那么就不存在最小树形图
                return -1;//返回-1
        }
        memset(id, -1, sizeof(id));//记录环的标号
        memset(visit, -1, sizeof(visit));//是否访问过
        int tn = 0;//环数
        in[root] = 0;//根节点清零
        for(int i=0; i<n; i++)//遍历每个节点,求最短弧的集合
        {
            res += in[i];//加入权值
            int v = i;
            while(visit[v]!=i&&id[v]==-1&&v!=root)//如果当前点没有被访问过,并且不是根节点,并且不在任何一个环上
            {
                visit[v] = i;
                v = pre[v];
            }
            if(id[v]==-1&&v!=root)
            {
                for(int u=pre[v]; u!=v; u=pre[u])
                {
                    id[u] = tn;
                }
                id[v] = tn++;
            }
        }
        if(tn==0)//没有环出现,则找到了最小树形图
            break;//跳出
        for(int i=0; i<n; i++)//收缩有向环
        {
            if(id[i]==-1)
            {
                id[i] = tn++;
            }
        }
        for(int i=0; i<m;)
        {
            v = Edge[i].v;
//            int u = Edge[i].u;
            Edge[i].u = id[Edge[i].u];
            Edge[i].v = id[Edge[i].v];
            if(Edge[i].u!=Edge[i].v)
                Edge[i++].cost -= in[v];
            else
                swap(Edge[i], Edge[--m]);
        }
        n = tn;
        root = id[root];
    }
    return res;
}
int main()
{
    int T;
    scanf("%d", &T);
    for(int t = 1;t<=T;t++)
    {
      int n, m;
      scanf("%d %d", &n, &m);
      for(int k=0;k<m;k++)
      {
         scanf("%d %d %d", &Edge[k].u, &Edge[k].v, &Edge[k].cost);
         if(Edge[k].u==Edge[k].v)
         Edge[k].cost = INF;
      }
      int res = zhuliu(0, n, m);
      if(res==-1)
      printf("Case #%d: Possums!\n", t);
      else
      printf("Case #%d: %d\n", t, res);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值