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

来源:互联网 发布:姚明nba前两场数据 编辑:程序博客网 时间:2024/06/07 04:00

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: xiyi, 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: xiyi, 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
23 31 2 101 3 102 3 103 31 2 101 3 102 3 11
 

Sample Output
20 121 2
 

Source
2017 Multi-University Training Contest - Team 8 
 

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;}

原创粉丝点击