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>
#include<cstring>
#include<string>
#include<algorithm>

using namespace std;
#define INF 0x3FFFFFF
#define MAXN 5555
struct edge
{
	int  u,v,w;
}e[9999999];
int n,en;
int pre[MAXN],in[MAXN],id[MAXN],vis[MAXN];
void add(int u,int v,int w)
{
	e[en].u=u;
	e[en].v=v;
	e[en++].w=w;
}
int zl(int root ,int vn)
{
	int ans=0;
	int cnt;
	while(1)
	{
		for(int i=0;i<vn;i++)
			in[i]=INF,id[i]=-1,vis[i]=-1;
		for(int i=0;i<en;i++)
		{
			if(in[e[i].v]>e[i].w && e[i].u!=e[i].v)
			{
				pre[e[i].v]=e[i].u;
				in[e[i].v]=e[i].w;
			}
		}
		in[root]=0;
		pre[root]=root;
		for(int i=0;i<vn;i++)
		{
			ans+=in[i];
			if(in[i]==INF)
				return -1;
		}
		cnt=0;
		for(int i=0;i<vn;i++)
		{
			if(vis[i]==-1)
			{
				int t=i;
				while(vis[t]==-1)
				{
					vis[t]=i;
					t=pre[t];
				}
				if(vis[t]!=i || t==root) continue;
				for(int j=pre[t];j!=t;j=pre[j])
					id[j]=cnt;
				id[t]=cnt++;
			}
		}
		if(cnt==0) break;
		for(int i=0;i<vn;i++)
			if(id[i]==-1)
				id[i]=cnt++;
		for(int i=0;i<en;i++)
		{
			int u,v;
			u=e[i].u;
			v=e[i].v;
			e[i].u=id[u];
			e[i].v=id[v];
			e[i].w-=in[v];
		}
		vn=cnt;
		root=id[root];
	}
	return ans;
}
int a[MAXN],pres[MAXN];
int main()
{
    int x,y,b,c,d,m;
    while(~scanf("%d%d",&n,&m))
    {
        if(!n&&!m) break;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),
            pres[i]=pres[i-1]+a[i]+1;
        en=0;
        int s=0;
        int t=pres[n]+1;
        for(int i=1;i<=n;i++)
        {
            for(int id=1;id<=a[i];id++)
            {
                add(pres[i-1]+id+1,pres[i-1]+id,0);
          //      printf("%d -> %d\n",pres[i-1]+id+1,pres[i-1]+id);
            }
            add(s,pres[i-1]+1,0);
       //     printf("%d -> %d\n",pres[i-1]+a[i]+1,t);
       //     printf("%d -> %d\n",s,pres[i-1]+1);
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d%d%d",&x,&y,&b,&c,&d);
            add(pres[x-1]+y+1,pres[b-1]+c+1,d);
    //        printf("%d -> %d\n",pres[x-1]+y+1,pres[b-1]+c+1);
        }
        int tmp=zl(0,t);
        if(tmp<0) puts("-1");
        else printf("%d\n",tmp);
    }
	return 0;
}

hdu 4966 最小树形图,布布扣,bubuko.com

时间: 2024-08-08 01:28:28

hdu 4966 最小树形图的相关文章

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 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 2121 Ice_cream’s world II (不定根最小树形图)

题目地址:HDU 2121 这题没有给定根.最容易想到的当然是暴力,枚举所有的根,但是TLE是显然的..为了处理不定根的情况,可以虚拟一个根,然后用这个根去跟所有的点连边,权值为其他所有权值的和+1,目的是防止成为最小树形图的一条边.然后跑出最小树形图后,那么这个虚拟根肯定跟一个实际根相连,这时候根就找到了,然后再在最终的总花费中减去虚拟的那条边的权值就可以了. 代码如下: #include <iostream> #include <string.h> #include <m

[tarjan+最小树形图] hdu 3072 Intelligence System

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3072 Intelligence System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1479    Accepted Submission(s): 653 Problem Description After a day, ALP

hdu 3072 有向图缩点成最小树形图计算最小权

题意,从0点出发,遍历所有点,遍历边时候要付出代价,在一个SCC中的边不要付费.求最小费用. 有向图缩点(无需建立新图,,n<=50000,建则超时),遍历边,若不在一个SCC中,用一个数组更新记录最小到达该连通分量的最小边权即可...边聊天,边1A,哈哈... #include<iostream> #include<stack> #include<queue> #include<cstdio> #include<cstring> usin

HDU 6141 I am your Father!(最小树形图)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6141 [题目大意] 给出一个有向图,求1点为根的最小树形图使得第n个点的直接父亲编号最小 [题解] 如果没有第n个点直接父亲编号最小的要求, 那么只要跑一遍朱刘算法即可,考虑到直接父亲最小的条件, 我们连向第n个点的所有边进行加权操作, 使得其在总边权相同的情况选取答案具有优先性 [代码] #include <cstdio> #include <algorithm> using n

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

http://acm.hdu.edu.cn/showproblem.php?pid=6141 题意: 求最大树形图. 思路: 把边的权值变为负值,那么这就是个最小树形图了,直接套模板就可以解决. 有个问题就是n结点的父亲结点的编号要尽量小,这里有个技巧可以用,权值编码,将所有边的权值都放大1000倍,对于和n相连的边,每条边在减去(n-u)的权值.这样就会去优先考虑编号小的边,而且因为权值最大为100,所以扩大1000是不会影响结果的. 1 #include<iostream> 2 #incl