题目概述
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", ×);//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