Alice's Chance 最大流

Alice, a charming girl, have been dreaming of being a movie star for long. Her chances will come now, for several filmmaking companies invite her to play the chief role in their new films. Unfortunately, all these companies will start making the films at the same time, and the greedy Alice doesn’t want to miss any of them!! You are asked to tell her whether she can act in all the films.
As for a film,

  1. it will be made ONLY on some fixed days in a week, i.e., Alice can only work for the film on these days;
  2. Alice should work for it at least for specified number of days;
  3. the film MUST be finished before a prearranged deadline.

For example, assuming a film can be made only on Monday, Wednesday and Saturday; Alice should work for the film at least for 4 days; and it must be finished within 3 weeks. In this case she can work for the film on Monday of the first week, on Monday and Saturday of the second week, and on Monday of the third week.
Notice that on a single day Alice can work on at most ONE film.

Input
The first line of the input contains a single integer T (1 <= T <= 20), the number of test cases. Then T cases follow. Each test case begins with a single line containing an integer N (1 <= N <= 20), the number of films. Each of the following n lines is in the form of “F1 F2 F3 F4 F5 F6 F7 D W”. Fi (1 <= i <= 7) is 1 or 0, representing whether the film can be made on the i-th day in a week (a week starts on Sunday): 1 means that the film can be made on this day, while 0 means the opposite. Both D (1 <= D <= 50) and W (1 <= W <= 50) are integers, and Alice should go to the film for D days and the film must be finished in W weeks.

Output
For each test case print a single line, ‘Yes’ if Alice can attend all the films, otherwise ‘No’.

Sample Input

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

Alice有好多电影要演,电影要求只能在一周的规定时间拍摄,并且规定在一定期限内拍摄不少于一个给定天数。Alice什么电影都不想错过,她想全接下来,她每天只能拍一部电影,现在求她能不能把这些电影全都演完。
根据题目中给出的数据量,最多只有350天,所以我们像日程表那样,把每一天的安排排出来。
设置一个源点,从源点连一条边到未来的350天,每条边的权值为1。之后根据给定的电影工作时间安排,把日程表的每一天连到可以在这一天工作的电影上,权值仍然为1,因为每一天只能拍一部。最后在电影和汇点之间连上一条边,权值为这个电影的最小工作时间。
建图之后跑最大流,判断这个图的最大流是否等于所有电影最小拍摄时间之和,如果等于表示可以都拍完;如果不等于,也就是小于,表示不能都拍完。


#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <string>

#define MAXN 400
#define filmSTAR 355
#define daySTAR 0
#define starNode 0
#define finishNode 380
#define INF 0x3f3f3f3f
#define ll long long
#define re return
#define getLen(name,index) name[index].size()
#define mem(a,b) memset(a,b,sizeof(a));

#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)

using namespace std;
struct Edge{
    int to;
    int cap;
    int rev;
};

bool work[8];
int cur[MAXN];
int level[MAXN];
vector<Edge> adj[MAXN];
inline void addEdge(int star,int finish,int cap);
int dinic();
void bfs();
int dfs(int star,int finish,int f);
int main(){
    ios::sync_with_stdio(false);

    int t;
    cin>>t;
    while(t--){
        int sum=0;
        int N,D,W;
        cin>>N;
        rep(i,1,N+1){
            rep(i,1,8){
                cin>>work[i];
            }

            cin>>D>>W;
            sum+=D;
            addEdge(i+filmSTAR,finishNode,D);
            rep(week,0,W){
                rep(day,1,8){
                    if(work[day])
                        addEdge(week*7+day+daySTAR,i+filmSTAR,1);
                }
            }
        }

        rep(i,1,351)
            addEdge(starNode,daySTAR+i,1);

        if(dinic()==sum)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;

        rep(i,0,MAXN)
            adj[i].clear();

    }

    re 0;
}
inline void addEdge(int star,int finish,int cap){
    adj[star].push_back((Edge){finish,cap,getLen(adj,finish)});
    adj[finish].push_back((Edge){star,0,getLen(adj,star)-1});
}
int dinic(){
    int sum=0,d;

    while(true){
        bfs();
        if(level[finishNode]<0)
            break;

        mem(cur,0);
        while(d=dfs(starNode,finishNode,INF),d>0){
            sum+=d;
        }
    }

    re sum;
}
void bfs(){
    mem(level,-1);
    level[starNode]=0;

    queue<int> Q;
    Q.push(starNode);
    while(!Q.empty()){
        int now=Q.front();
        Q.pop();

        int dep=level[now];
        rep(i,0,getLen(adj,now)){
            Edge &e=adj[now][i];

            if(e.cap>0 && level[e.to]<0){
                level[e.to]=dep+1;
                Q.push(e.to);
            }
        }
    }
}
int dfs(int star,int finish,int f){
    if(star==finish)
        re f;

    for(int &i=cur[star];i<getLen(adj,star);i++){
        Edge &e=adj[star][i];

        if(e.cap>0 && level[e.to]==level[star]+1){
            int d=dfs(e.to,finish,min(f,e.cap));
            if(d>0){
                e.cap-=d;
                adj[e.to][e.rev].cap+=d;
                re d;
            }
        }
    }
    re -1;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值