hdu3572 Task Schedule(Dinic判断是否满流)


http://acm.hdu.edu.cn/showproblem.php?pid=3572

题意:给你n个任务,m个机器,每个任务有花费时间w、开始时间s、结束时间t,每个任务可以以每天为单位断断续续执行,但在同一天一台机器只能执行一个任务。问是否存在一个可行的时间安排能够使他们全部完成。


ps:因为引用,贡献了20多个TLE。。都怪我蠢。。


思路:这题难在建图。要想达到目的有两个指标,一个是做完全部任务,另一个就是不超过时间限制,于是就把这两项当成分界线。建立一个超级源点连向所有任务,容量为该任务所需要的天数。每个任务连向该任务可以合法完成的所有工作日,容量为1,代表每天工作量为1。每个工作日连向超级汇点,容量为机器数量,表示每天的最大加工量。如果从源点到汇点的最大流等于所有工作所需的时间和,就说明中间没有任何一个任务时间冲突造成的无法完成,则总体安排可以完成。整体思路还需好好总结。


[前方高能]


直到这道题才发现我的模板有问题。。就是这一段:(dfs中的)

for(int& i = cur[x]; i != -1; i = edge[i].next)
一直用的邻接表前面都没加引用,这里不加引用竟然超时??在这里愣是懵逼了好久。。好在有人提醒,下面有递归操作!!

f = dfs(E.to, min(res, E.cap-E.flow), endd);

但是递归操作又怎样呢?注意我们这里处理的是前向星,在这里建议看下这位大牛对前向星的理解。从这篇博客我们知道,head[i]保存的是以i为起点的所有边中编号最大的那个。就拿那个大牛博客里的例子来了:(如果想懂一定要看完他的这篇文章!)

edge[0].to = 2;     edge[0].next = -1;      head[1] = 0;
edge[1].to = 3;     edge[1].next = -1;      head[2] = 1;
edge[2].to = 4;     edge[2],next = -1;      head[3] = 2;
edge[3].to = 3;     edge[3].next = 0;       head[1] = 3;
edge[4].to = 1;     edge[4].next = -1;      head[4] = 4;
edge[5].to = 5;     edge[5].next = 3;       head[1] = 5;
edge[6].to = 5;     edge[6].next = 4;       head[4] = 6;

遍历以节点1为起点的三条边,编号分别为0,3,5。


如果没有递归,比如我们遍历起点为1的边,head[1]=5,也就是先遍历编号为5的边,然后是i = edge[5].next等于3,找到了编号为3的边,然后继续i = edge[3].next等于0,找到编号为0的边。这里加了递归,我们遍历起点为1的边,head[1]=5,然后是i = edge[5].next等于3。(虽然直观上在分层的dfs中下一次不可能遍历相同起点的边,但是我们这里注意,尼玛可能有重边啊!!dfs又不是一次深搜就找到路线,即使对于分层的也需要回溯查找,这样就完全有可能经过同一个起点!!)那么见证奇迹的时刻来了,递归下去同样是对i赋值head[1]依然等于5啊,这个5是不是遍历过了?!!那下一次找编号为0的边,不是还要遍历3和5?这就是超时的原因所在啊!!


解决方法就是前面加个引用,做到head和i的同步更新,不过因为要多次dfs,所以复制出一个cur,对cur更新。


本题是用前向星做的,没用前向星的请直接无视= =。话说前面两题都是用错的模板过得,说明数据不怎么样嘛!不过也有看到不加引用的前向星。。orz。。不过通过这道题,使我对前向星有了一个更加深刻的理解,想必也是极好的。。不说了把前面两个模板改了555


#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <queue>
#include <stack>
#include <ctype.h>

using namespace std;

typedef long long LL;

const int N = 1000005;
const int INF = 0x3f3f3f3f;

int head[N], dis[N], cur[N];
bool vis[N];
int n, m, cnt, sink, sum;

struct Edge
{
    int to, cap, flow, next;
}edge[N];

void add(int u, int v, int w)
{
    edge[cnt] = (struct Edge){v, w, 0, head[u]};
    head[u] = cnt++;
    edge[cnt] = (struct Edge){u, 0, 0, head[v]};
    head[v] = cnt++;
}

bool bfs(int start, int endd)
{
    memset(dis, -1, sizeof(dis));
    memset(vis, false, sizeof(vis));
    queue<int>que;
    dis[start] = 0;
    vis[start] = true;
    que.push(start);
    while(!que.empty())
    {
        int u = que.front();
        que.pop();
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            Edge E = edge[i];
            if(!vis[E.to] && E.flow<E.cap)
            {
                dis[E.to] = dis[u]+1;
                vis[E.to] = true;
                if(E.to == endd) return true;
                que.push(E.to);
            }
        }
    }
    return false;
}


int dfs(int x, int res, int endd)
{
	if(x == endd || res == 0) return res;
	int flow = 0, f;
	for(int& i = cur[x]; i != -1; i = edge[i].next)
	{
		Edge E = edge[i];
		if(dis[E.to] == dis[x]+1)
		{
		    f = dfs(E.to, min(res, E.cap-E.flow), endd);
            if(f>0)
            {
                edge[i].flow += f;
                edge[i^1].flow -= f;
                flow += f;
                res -= f;
                if(res == 0) break;
            }
		}
	}
	return flow;
}


int max_flow(int start, int endd)
{
    int flow = 0;
    while(bfs(start, endd))
    {
        memcpy(cur, head, sizeof(head));
        flow += dfs(start, INF, endd);
    }
    return flow;
}

void init()
{
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void getmap()
{
    int s, t, w, last;
    last = 0;
    sum = 0;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d%d%d", &w, &s, &t);
        add(0, i, w);
        last = max(last, t);
        for(int j = s; j <= t; j++)
            add(i, n+j, 1);
        sum += w;
    }
    sink = n+last+1;
    for(int i = n+1; i <= n+last; i++)
        add(i, sink, m);
}

int main()
{
  //  freopen("in.txt", "r", stdin);
    int t0, Case = 1;
    scanf("%d", &t0);
    while(t0--)
    {
        init();
        getmap();
        int ans = max_flow(0, sink);
        if(ans == sum) printf("Case %d: Yes\n\n", Case++);
        else printf("Case %d: No\n\n", Case++);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的体育馆管理系统,源码+数据库+毕业论文+视频演示 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本体育馆管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此体育馆管理系统利用当下成熟完善的SpringBoot框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的Mysql数据库进行程序开发。实现了用户在线选择试题并完成答题,在线查看考核分数。管理员管理收货地址管理、购物车管理、场地管理、场地订单管理、字典管理、赛事管理、赛事收藏管理、赛事评价管理、赛事订单管理、商品管理、商品收藏管理、商品评价管理、商品订单管理、用户管理、管理员管理等功能。体育馆管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 关键词:体育馆管理系统;SpringBoot框架;Mysql;自动化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值