HDU 6141 I am your Father!(最小树形图+权值编码)

87 篇文章 0 订阅

I am your Father!

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 173    Accepted Submission(s): 37


Problem Description
> Darth Vader: "Obi-Wan never told you what happened to your father."
>
> Luke Skywalker: "He told me enough! He told me you killed him!"
>
> Darth Vader: "No, I am your father."
>
> — Vader and Luke, on Cloud City

A list of  n  force-aware males numbered  1  through  n  were found. They are the chosen ones that will bring balance to the force. Being listed at the first place, Anakin Skywalker is the ancestor of all rest  n1  persons.

Interestingly, everyone else claims he is the father of some others, causing serious troubles. Fortunately, you found the list also comes with these claims and their likelihood. Your task is to find the true father of Nikana, the last one in the list (numbered  n ).

There are  m  claims in the list. The  i -th claim consists of three integers:  xi yi , and  wi , indicating that the  xi -th person claims he is the father of the  yi -th person, with a likelihood of  wi .

Your task is to find a global assignment that assigns each person (except Anakin Skywalker) to someone in the list, i.e., find  f(u)  such that:

1. Everyone is assigned a father, i.e.,  f(u){1,2,,n}  for all  u{2,3,,n} .
2. Each one's assigned father claims their relationship, i.e., for all  u , there exists a claim  i  in the claims such that  f(u)=xiu=yi .
3. Nobody is an ancestor of himself in the assignment, directly or indirectly.
4. The assignment maximizes the sum of the likelihood of the father-and-son relationships, i.e.,  W=iwi  if  f(u)=xiu=yi  is in the assignment.

You should find the father of Nikana (the person numbered  n ) in such an optimized assignment. If multiple assignments have the same optimal likelihood  W , you should find the assignment that minimizes the lexical number of his father, i.e., minimizes  f(n)  at the same time has an optimal assignment likelihood  W . That makes Nikana closer to Anakin Skywalker.
 

Input
There are multiple test cases in the input file. The first line of the input gives the number of test cases  T , then followed by  T  test cases.

The first line of a test case contains  n  ( 1n103 ) and  m  ( m104 ), the number of persons and the number of claims, respectively.

Then  m  lines follows. The  i -th line contains three integers:  xi yi , and  wi  indicating the claimed father, son, and likelihood.  1wi100  is guaranteed. Nobody will claim someone as his son twice.
 

Output
For each test case, output one line containing two space-separated integers, the maximum likelihood  W  and the father of Nikana.
 

Sample Input
  
  
2 3 3 1 2 10 1 3 10 2 3 10 3 3 1 2 10 1 3 10 2 3 11
 

Sample Output
  
  
20 1 21 2
 

Source
 

Recommend
liuyiding
 

题目大意:

    给你一个有向图,求以1为根的最大树形图,并且要使结点n的父亲编号字典序最小。


解题思路:

    十分明显的最小树形图,我们只需要把权值乘上-1就可得到使得答案最大。问题是怎么使得结点n的父亲字典序最小,通过观察朱刘算法的实现过程可以发现,由于算法中的缩点,在实现求解的过程中一定没有办法通过确定更新顺序之类的修改保证字典序最小。

    由于我们只是要让指向结点n的父亲字典序最小,我们可以通过权值编码让指向n起点字典序小的边的权值小一点就可以优先选择字典序最小的边了。为了使字典序的影响比初始权值小,把所有初始权值乘上最大点数1000再对指向n的边加上起点编号。这样重新编码后就可以保证在不影响原算法结果的前提下使得n的父亲最小。最终答案就是对朱刘算法除1000,父亲编号就是对1000取模。


AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <string>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define fi first
#define se second
#define mem(a,b) memset((a),(b),sizeof(a))

const int MAXV=1000+3;//最大顶点数
const int MAXE=10000+3;//最大边数

struct Edge
{
    int u, v;
    int cost;
}edge[MAXE];//边集

int V,E;//顶点数,边数
int pre[MAXV],id[MAXV],vis[MAXV];
int in[MAXV];

int zhuliu(int root)//返回最小花费
{
    int res=0;
    while(true)
    {
        for(int i=0;i<V;++i)
            in[i]=INF;
        for(int i=0;i<E;++i)
            if(edge[i].u!=edge[i].v&&edge[i].cost<in[edge[i].v])
            {
                pre[edge[i].v]=edge[i].u;
                in[edge[i].v]=edge[i].cost;
            }
        for(int i=0;i<V;++i)
            if(i!=root&&in[i]==INF)
                return -1;//不存在最小树形图
        int tn=0;//新图结点数
        for(int i=0;i<V;++i)
        {
            id[i]=-1;
            vis[i]=-1;
        }
        in[root]=0;
        for(int i=0;i<V;++i)
        {
            res+=in[i];
            int v=i;
            while(vis[v]!=i&&id[v]==-1&&v!=root)
            {
                vis[v]=i;
                v=pre[v];
            }
            if(v!=root&&id[v]==-1)
            {
                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<V;++i)
            if(id[i]==-1)
                id[i]=tn++;
        for(int i=0;i<E;)
        {
            int v=edge[i].v;
            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[--E]);
        }
        V=tn;
        root=id[root];
    }
    return res;
}

int main()
{
    int T_T;
    scanf("%d", &T_T);
    while(T_T--)
    {
        scanf("%d%d", &V, &E);
        for(int i=0;i<E;++i)
        {
            scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);
            --edge[i].u;//令下标从0开始
            --edge[i].v;
            edge[i].cost*=-1000;
            if(edge[i].v==V-1)
                edge[i].cost+=edge[i].u;
        }
        int ans=zhuliu(0);
        printf("%d %d\n", (-ans+999)/1000, (-ans+999)/1000*1000+ans+1);
    }
    
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值