HDU 4966 GGS-DDU

题意:

你有n个课程  每个课程有一个规定的毕业学分  修学分有m种方式  每种方式要求先修到x课程x‘学分以上才能花费money去修y课程并且将学分修到y‘  问  最少花费多少可以毕业

思路:

一开始想费用流  建完图发现一个问题解决不掉  那就是  一条边如果流过多次怎样才能让费用只计算一次  所以换思路

我们知道  为了应付“ 学分修到y‘ ”这个条件  高层学分一定要“覆盖”低层学分  那么就想到以每个学分为一个点  高层向低层连边  费用为0  同时修学分的方式是输入的  直接建边  费用为输入费用  一开始只能走到0学分  所以超级源点向所有0学分连边  费用0  那么此时我们想要的是从源点花最小费用走到所有点  这就是有向图最小生成树  即最小树形图

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define M 610
#define inf 2000000000

int n, m, ans, tot, S;
int head[M], id[M], in[M], pre[M], vis[M], node[M][M], s[M];
struct ed {
    int u, v, w, next;
} ed[M * M];

int ZL(int root, int V, int E) {
    int ret = 0;
    for (;;) {
        for (int i = 0; i < V; i++) {
            id[i] = -1;
            vis[i] = -1;
            in[i] = inf;
        }
        for (int i = 0; i < E; i++) {
            int u = ed[i].u;
            int v = ed[i].v;
            if (ed[i].w < in[v] && u != v) {
                pre[v] = u;
                in[v] = ed[i].w;
            }
        }
        for (int i = 0; i < V; i++) {
            if (i == root)
                continue;
            if (in[i] == inf)
                return -1;
        }
        int cnt = 0;
        in[root] = 0;
        for (int i = 0; i < V; i++) {
            ret += 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] = cnt;
                id[v] = cnt++;
            }
        }
        if (cnt == 0)
            break;
        for (int i = 0; i < V; i++)
            if (id[i] == -1)
                id[i] = cnt++;
        for (int i = 0; i < E; i++) {
            int u = ed[i].u;
            int v = ed[i].v;
            ed[i].u = id[u];
            ed[i].v = id[v];
            if (id[u] != id[v])
                ed[i].w -= in[v];
        }
        V = cnt;
        root = id[root];
    }
    return ret;
}

void add(int U, int V, int W) {
    ed[tot].u = U;
    ed[tot].v = V;
    ed[tot].w = W;
    ed[tot].next = head[U];
    head[U] = tot++;
}

int main() {
    int i, j, k, u, v, tmp;
    while (scanf("%d%d", &n, &m) != EOF) {
        if (!n && !m)
            break;
        k = 0;
        for (i = 1; i <= n; i++) {
            scanf("%d", &s[i]);
            for (j = 0; j <= s[i]; j++)
                node[i][j] = k++;
        }
        S = k++;
        tot = 0;
        memset(head, -1, sizeof(head));
        for (i = 1; i <= n; i++) {
            add(S, node[i][0], 0);
            for (j = 1; j <= s[i]; j++)
                add(node[i][j], node[i][j - 1], 0);
        }
        for (i = 1; i <= m; i++) {
            scanf("%d%d", &u, &v);
            tmp = node[u][v];
            scanf("%d%d", &u, &v);
            v = node[u][v];
            u = tmp;
            scanf("%d", &tmp);
            add(u, v, tmp);
        }
        ans = ZL(S, k, tot);
        printf("%d\n", ans);
    }
    return 0;
}

HDU 4966 GGS-DDU

时间: 2024-08-06 13:17:49

HDU 4966 GGS-DDU的相关文章

hdu 4966 GGS-DDU (最小树形图)

比较好的讲解:http://blog.csdn.net/wsniyufang/article/details/6747392 view code//首先为除根之外的每个点选定一条入边,这条入边一定要是所有入边中最小的. //现在所有的最小 入边都选择出来了,如果这个入边集不存在有向环的话,我们 //可以证明这个集合就是该图的最小树形图.这个证明并不是很难.如果存在有向 //环的话,我们就要将这 个有向环所称一个人工顶点,同时改变图中边的权.假 //设某点u在该环上,并设这个环中指向u的边权是in

HDU 4966 GGS-DDU 最小树形图

题意: 给定n个技能,m个限制 下面是每个技能满级的级数 开始每个技能都是0级. m个限制 (c,l1) (d,l2) cost 若c技能已经>=l1级,那么把点亮d技能 从0级一路点到l2级的花费是cost ..他说的好有道理,我竟无言以对 _(:зゝ∠)_ 最小树形图,用0做根,触发每个技能的0级花费是0 若已经点亮技能的x级,则点亮该技能的x-1级花费就是0 #include <stdio.h> #include <string.h> #include <iost

hdu 4966 最小树形图

将每门课等级拆成0,1,2,3...a[i]个点,对每个等级大于0的点向它低一级连边,权值为0[意思是,若修了level k,则level(0~k)都当做修了] 将输入的边建边,权值为money[i]. 建立根节点,向每个level 0的点连边,权值为0[因为初始level 0的都修了] 由于题目要求每门课都必须达到最大level,也就是对应图中根节点能到达所有点,问题就变成了求无向图的最小生成树. #include<iostream> #include<cstdio> #incl

HDU 4966 GGS-DDU (最小树形图-朱刘算法)

题目地址:HDU 4966 刚开始没看清总级别只有500这一条件,看成了每一个都是500..然后建图思路就想歪了.....后来才发现是总共只有500..那么建图就很简单了..把每个科目的每个等级都设为一个点,把所有的0等级设为同一个树根.然后把所有科目的高等级向低等级连一条权值为0的有向边,第一个作用是保证最后的最小树形图是所有点都可达,第二个作用是保证每节课的的所需等级,只要达到高等级,那么使低等级也符合.然后再对每节课连边即可. 代码如下: #include <iostream> #inc

HDU 4966 GGS-DDU(最小树形图)

n个技能,每个技能有0-a[i]的等级,m个课程,每个课程需要前置技能c[i]至少达到lv1[i]等级,效果是技能d[i]达到lv2[i]等级,花费w[i]. 输出最小花费使得全技能满级(初始全技能0等级) n<=50,Σa[i]<=500,m<=2000 点<=551,边<=2000+50+Σ((a[i]+1)*a[i]/2) Σw[i]<=2000*1000<0x3f3f3f3f 比赛时候完全不在状态,什么题都想不到,坑队友了... 最小树形图-做过tarja

hdu 4965 矩阵快速幂 矩阵相乘性质

Fast Matrix Calculation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 170    Accepted Submission(s): 99 Problem Description One day, Alice and Bob felt bored again, Bob knows Alice is a gir

hdu 4961 数论 o(nlogn)

Boring Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 60    Accepted Submission(s): 30 Problem Description Number theory is interesting, while this problem is boring.   Here is the probl

HDU:GGS-DDU

HDU:GGS-DDU 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4966 题目大意:有$n$个课程,初始都在等级$0$,每个课程需要达到等级$a[i]$.满足$x$课程等级大于等于$dx$时,可花费$w$使得$y$课程等级达到$dy$,求最少需要多少钱? 最小树形图 一个有向图若存在从某个点开始的到达所有的的一个最小生成树,则它就是最小树形图. 引自http://www.cnblogs.com/vongang/archive/2012/07/

hdu 4960 记忆化搜索 DP

Another OCD Patient Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 490    Accepted Submission(s): 180 Problem Description Xiaoji is an OCD (obsessive-compulsive disorder) patient. This morni