POJ 1698 Alice's Chance

题目:Alice 要拍电影,每一天只能参与一部电影的拍摄,每一部电影只能在 Wi 周之内的指定的日子拍摄,总共需要花 Di 天时间,求能否拍完所有电影。

典型的二分图多重匹配,这里用了最大流的 dinic 算法。构图:源点向每部电影流容量为 Di 的边,电影向允许的日期流容量为 1 的边,每一天向汇点流容量为 1 的边。跑一次最大流,如果最大流等于 D,那么就可以。

一开始用了多路增广忘了把流量为零的 d 设为 -1……悲剧……TLE 了。

代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;

const int MAXV = 520, FILM = 400, MAXE = 15000, INF = 0x3f3f3f3f;
struct edge{
    int to, cap, next;
    edge(){};
    edge(int to_, int cap_, int next_):to(to_), cap(cap_), next(next_){};
} es[MAXE];
int head[MAXV], d[MAXV], que[MAXV], tot, tmp[8];

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

inline void add2(const int &a, const int &b, const int &cap){
//  printf("%d---%d: %d\n", a, b, cap);
    es[tot] = edge(b, cap, head[a]); head[a] = tot++;
    es[tot] = edge(a,   0, head[b]); head[b] = tot++;
}

bool bfs(int s, int t){
    memset(d, -1, sizeof(d));
    d[s] = 0;
    int hh = 0, tt = 1;
    que[0] = s;
    while(hh < tt){
        int u = que[hh++];
        if(u == t)return true;
        for(int i = head[u]; ~i; i = es[i].next){
            int v = es[i].to;
            if(d[v] == -1 && es[i].cap){
                d[v] = d[u] + 1;
                que[tt++] = v;
            }
        }
    }
    return false;
}

int dfs(int s, int t, int low){
    if(s == t) return low;
    int ret = 0;
    for(int i = head[s]; ~i; i = es[i].next){
        int v = es[i].to, f = es[i].cap;
        if(d[v] == d[s] + 1 && f && (f = dfs(v, t, min(low - ret, f)))){
            es[i].cap -= f;
            es[i^1].cap += f;
            ret += f;           //多路增广 
            if(ret == low) break;
        }
    }
    if(!ret) d[s] = -1; //这里剪枝非常重要 
    return ret;
}

int dinic(int s, int t){
    int ans = 0;
    while(bfs(s, t)){
        ans += dfs(s, t, INF);
    }
    return ans;
}

int main(){
    freopen("in.txt", "r", stdin);
    int T, N, D, W;
    scanf("%d", &T);
    while(T--){
        init();
        int sum = 0, day = 0;
        scanf("%d", &N);
        for(int i = 0; i < N; ++i){
            for(int j = 1; j <= 7; ++j) scanf("%d", &tmp[j]);
            scanf("%d%d", &D, &W);
            day = max(day, W);
            add2(0, FILM + i, D);
            sum += D;
            for(int w = 0; w < W; ++w){
                for(int j = 1; j <= 7; ++j){
                    if(tmp[j]) add2(FILM + i, w * 7 + j, 1);
                }
            }
        }
        for(int i = day * 7; i > 0; --i){
            add2(i, 500, 1);
        }
        int ans = dinic(0, 500);
        if(ans == sum) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
posted @ 2016-02-09 13:07  will7101  阅读(183)  评论(0编辑  收藏  举报