Alice's Chance poj1698 最大流

31 篇文章 0 订阅

Description


有n部电♂影,且每部电影至少要出演d天,这部电影可以拍w周,给出7个0或1的数字表示这一天能不能拍某电影,求是否能拍完所有电影

Code


网络流漏掉好多题(汗

开始想的是直接从原点连边到日期,结果发现这样是行不通的。于是加入一列点表示电影,从原点连一条边到电影节点容量为需要的天数

日期很容易想到是可以拆分的,那么7*50=350,算上20个电影的点370,那么我们只要开370*370的矩阵就行了

还有就是源点汇点的边最好一次性加完不然有重边的可能

神奇的地方在于不用矩阵会TLE,蒟蒻表示不懂 求解释

Code


#include <stdio.h>
#include <string.h>
#include <queue>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define fill(x, t) memset(x, t, sizeof(x))
#define N 372
#define INF 0x3f3f3f3f
using namespace std;
int rc[N][N], dis[N], v[10];
inline void addEdge(int x, int y, int w){
    rc[x][y] += w;
}
inline int bfs(int st, int ed){
    fill(dis, -1);
    dis[st] = 1;
    queue<int>q;
    q.push(st);
    while (!q.empty()){
        int now = q.front(); q.pop();
        rep(i, 1, N - 1){
            if (rc[now][i] > 0 && dis[i] == -1){
                dis[i] = dis[now] + 1;
                q.push(i);
                if (i == ed){
                    return 1;
                }
            }
        }
    }
    return 0;
}
inline int min(int x, int y){
    return x<y?x:y;
}
inline int find(int now, int mn, int ed){
    if (now == ed || !mn){
        return mn;
    }
    int ret = 0;
    rep(i, 1, N - 1){
        if (rc[now][i] > 0 && dis[now] + 1 == dis[i]){
            int d = find(i, min(rc[now][i], mn - ret), ed);
            rc[now][i] -= d;
            rc[i][now] += d;
            ret += d;
            if (ret == mn){
                break;
            }
        }
    }
    return ret;
}
inline int dinic(int st, int ed){
    int mxFlow = 0;
    while (bfs(st, ed)){
        mxFlow += find(st, INF, ed);
    }
    return mxFlow;
}
int main(void){
    int T;
    scanf("%d", &T);
    int ST = 0, ED = N - 1;
    while (T --){
        int n;
        scanf("%d", &n);
        int d = 0;
        fill(rc, 0);
        rep(i, 1, n){
            rep(j, 1, 7){
                scanf("%d", &v[j]);
            }
            int tmpD, w;
            scanf("%d%d", &tmpD, &w);
            d += tmpD;
            addEdge(ST, i + 350, tmpD);
            rep(k, 0, w - 1){
                rep(j, 1, 7){
                    if (v[j]){
                        addEdge(i + 350, k * 7 + j, 1);
                    }
                }
            }
        }
        rep(i, 1, 350){
            addEdge(i, ED, 1);
        }
        int ans = dinic(ST, ED);
        if (ans == d){
            printf("Yes\n");
        }else{
            printf("No\n");
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值