HD4699&2014 Multi-University Training Contest 9 1007 GGS-DDU 最小树形图

7 篇文章 0 订阅

题目链接点这儿

给你一些课程,每个课程都分为多级。再给出你一些关系,如果你上了课i的level d1,那么你的课j的level 就提升至d2。这个提升的意思就是你可以上课j所有的level <= d2的课时。

问你有没有可能所有课程都达到最高级。

裸的最小树形图。。。课与课的关系是一些建边关系,另外就是因为你打到level d后,所有<= d的该门课你就都能上了,所以要再加上一些反向边。最后加一个连着每门课level0的一个源点,,,,跑一个最小树形图就完了。。。


交到hdu是0ms。。。。完全没有trick。。。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cstring>

using namespace std;

typedef int type;
const int inf = 1000;

struct node {
	int s, e;
	type l;
};

int sum[55];
node ed[500*50+2000+10];

int num;
void add(int s, int e, type l) {
	ed[num].s = s;
	ed[num].e = e;
	ed[num].l = l;
	num++;
}

void init() {
	num = 0;
	sum[0] = 0;
}

int n, S;
int pre[50*500+10], id[50*500+10], vis[50*500+10];
type in[50*500+10];

type Directed_MST(int root ,int NV , int NE){
    type ret = 0 ;
    while(1){
        for (int i = 0 ; i < NV ; i ++ )in[i] = inf ;
        for (int i = 0 ; i < NE ; i ++ ){
            int s = ed[i].s ;
            int e = ed[i].e ;
            if(ed[i].l < in[e] && s != e){
                pre[e] = s ;
                in[e] = ed[i].l ;
            }
        }
        for (int i = 0 ; i < NV ; i ++ ){
            if(i == root)continue ;
//			printf("in[%d] = %d\n", i, in[i]);
            if(in[i] == inf)return -1 ;
        }
        int cntnode = 0 ;
        memset(vis ,-1, sizeof vis) ;
        memset(id ,-1, sizeof vis) ;
        in[root] = 0 ;
        for (int i = 0 ; i < NV ; 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] = cntnode ;
                }
                id[v] = cntnode ++ ;
            }
        }

        if(cntnode == 0)break ;
        for (int i = 0 ; i < NV ; i ++ ){
            if(id[i] == -1)id[i] = cntnode ++ ;
        }
        for (int i = 0 ; i < NE ; i ++ ){
            int s = ed[i].s ;
            int e = ed[i].e ;
            ed[i].s = id[s] ;
            ed[i].e = id[e] ;
            if(ed[i].s != ed[i].e){
                ed[i].l -= in[e] ;
            }
        }
        NV = cntnode ;
        root = id[root] ;
    }
    return ret ;
}

int a[55];

int main() {
//	freopen("1007.in", "r", stdin);
//	freopen("output.txt", "w", stdout);
	int n, m;
	while(scanf("%d%d", &n, &m) && n) {
		init();
		for(int i = 0; i < n; i++) {
			scanf("%d", &a[i]);
			sum[i+1] = sum[i] + a[i]+1;
		}
		for(int i = 0; i < n; i++) {
			add(sum[n], sum[i], 0);
			for(int j = sum[i+1] - 1; j > sum[i]; j--)
				add(j, j-1, 0);
		}
		int c, l1, d, l2, cost;
		for(int i = 1; i <= m; i++) {
			scanf("%d%d%d%d%d", &c, &l1, &d, &l2, &cost);
			add(sum[c-1]+l1, sum[d-1]+l2, cost);
		}
		for(int i = 0; i < num; i++)
			printf("%d %d %d\n", ed[i].s, ed[i].e, ed[i].l);
		printf("%d\n", Directed_MST(sum[n], sum[n]+1, num));
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值