poj 1698

题目概述

alice接了N部电影的拍摄工作,所有电影在同一天开工,每周只有固定几天拍,其余时间不拍,电影必须在w周内拍完,alice至少需要去拍d天,问alice能否完成所有电影拍摄
alice每天只能去拍一部电影,每周第一天是周日

时限

1000ms/3000ms

输入

第一行整数times,其后times组数据,每组数据第一行整数N,其后N行,每行九个整数,前七个只有1或0,1表示每周这一天可拍,0反之,其后是d,w

限制

1<=times<=20;1<=N<=20;1<=d<=50;1<=w<=50

输出

每行一个字符串,若能完成所有拍摄,为Yes,否则为No

样例输入

2
2
0 1 0 1 0 1 0 9 3
0 1 1 1 0 0 0 6 4
2
0 1 0 1 0 1 0 9 4
0 1 1 1 0 0 0 6 2

样例输出

Yes
No

讨论

图论,应该算是二分图,但还没看到那部分,只能先用网络流处理,利用Isap+gap优化,主要还是构图,将每一天看做一个节点,编号0到349,因为最多50周,电影也看做节点,编号350到369,然后虚构一个源点370,汇点371,从源点出发流向每部电影,流量就是需要拍摄的天数,从每部电影到拍摄周内拍摄的那些天,流量是1,因为每天只能拍一部,同理这些天都连接到汇点,流量也是1,如此,若能全拍,则最大流量应为所有电影需要拍摄天数和
实现层次上,isap的gap优化不能垄断所有return,因为程序可能不从gap优化结束,而是从原始while判断条件结束,虽然有点不可思议,但确实如此,所有层次都有剩余,但源点已经被排除了,不再有最短路,程序结束,着实不知道如何发生的,好在并不难修改,给fun函数添加正常return出口,而gap优化改为break出while循环,这样就能照顾到所有情况了,这样说有点抽象,代码里会体现

题解状态

728K,16MS,C++,1777B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 374
#define memset0(a) memset(a,0,sizeof(a))

int N, S = 370, T = 371;//电影总数 以及虚构的源点汇点 这两点编号是固定的
int R[MAXN][MAXN], dis[MAXN], from[MAXN], gap[MAXN];//isap四大数组 残量矩阵 层次 父节点编号 每个层次的节点数
bool mk[7];//marked 用于将每周拍摄时间进行构图
queue<int>q;//bfs辅助队
bool fun()
{
    int sum = 0;//所有电影合计拍摄天数
    for (int p = 0; p < N; p++) {
        for (int i = 0; i < 7; i++)
            scanf("%d", &mk[i]);//input
        int d, w;//拍摄需求天数 拍摄周数
        scanf("%d%d", &d, &w);//input
        sum += d;
        R[S][p + 350] = d;//将源点与电影连接 残量是需求天数
        for (int i = 0; i < 7; i++) {//完成电影到每天再到汇点的构图
            if (!mk[i])//这天不拍 直接跳过
                continue;
            for (int u = 0; u < w; u++)
                R[p + 350][i + 7 * u] = R[i + 7 * u][T] = 1;//将电影与拍摄周内拍摄日相连 拍摄日再连到汇点 残量都是1
        }
    }
    N = 372;//既然汇点是371 那么N就是372了 虽然有点浪费 但好在数据规模小
    for (int p = 0; p < N; p++)//初始化层次数组 不能直接用0 这点在poj 1273里被卡了好几次 因为0在N范围内 后面可能会被视为可行边
        dis[p] = N;//初始化为N就足矣 因为在范围内的两点 最远不过N-1的层次差
    dis[T] = 0;//汇点到自己是0层次 下面是bfs 这些都是一样的
    gap[0]++;
    q.push(T);
    while (!q.empty()) {
        int a = q.front();
        q.pop();
        for (int p = 0; p < N; p++)
            if (dis[p] == N&&R[p][a]) {
                q.push(p);
                dis[p] = dis[a] + 1;
                gap[dis[p]]++;
            }
    }
    int most = 0, cur = S, flow = INF;//下面是isap算法主体
    while (dis[S] < N) {
        int p;
        for (p = 0; p < N && (!R[cur][p] || dis[cur] != dis[p] + 1); p++);
        if (p != N) {
            from[p] = cur;
            flow = min(flow, R[cur][p]);
            cur = p;
            if (cur == T) {
                most += flow;
                while (cur != S) {
                    p = from[cur];
                    R[p][cur] -= flow;
                    R[cur][p] += flow;
                    cur = p;
                }
                flow = 1;
            }
        }
        else {
            if (!--gap[dis[cur]])
                break;
            dis[cur] = N;
            for (int p = 0; p < N; p++)
                if (R[cur][p] && dis[cur] > dis[p] + 1)
                    dis[cur] = dis[p] + 1;
            gap[dis[cur]]++;
            if (cur != S)
                cur = from[cur];
        }
    }
    return most == sum;//算法现在有了正常的出口 没有这行结果必然会错
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    int times;
    scanf("%d", &times);//input
    while (times--) {
        scanf("%d", &N);//input
        if (fun())
            printf("Yes\n")//output;
        else
            printf("No\n");//output
        memset0(R);
        memset0(gap);//dis有初始化 from会被覆盖 这两个需要初始化
    }
}

EOF

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值