(3ms)
将x23看作值为0的源点建图,在遍历到边的时候根据当前枚举的x23的值临时计算边的权
C++ 代码
#include<iostream>
#include<cstring>
using namespace std;
const int N = 26, M = 100;
int r[24], c[24], n, m;
int idx, h[N], w[M], e[M], ne[M], d[N], cnt[N], q[N];
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
bool spfa()
{
memset(cnt, 0, sizeof cnt);
memset(d, -0x3f, sizeof d);
memset(st, 0, sizeof st);
int hh = 0, tt = 1;
q[0] = 23;
d[23] = 0;
while(hh != tt)
{
int u = q[hh++];
if(hh == N) hh = 0;
st[u] = false;
for(int i = h[u]; ~i; i = ne[i])
{
int v = e[i], w0 = w[i];
if(u == 23 && v == 22) w0 = w[i] + m;
else if((v == 23 && (u == 22 || u == 15)) || (v < 7 && u == v + 16)) w0 = w[i] - m;
else w0 = w[i];
if(d[v] < d[u] + w0)
{
d[v] = d[u] + w0;
cnt[v] = cnt[u] + 1;
if(cnt[v] >= 24)
return true;
if(!st[v])
{
st[v] = true;
q[tt++] = v;
if(tt == N) tt = 0;
}
}
}
}
return false;
}
int main()
{
int T;
cin >> T;
while(T--)
{
for(int i = 0; i < 24; ++i) cin >> r[i];
cin >> n;
for(int i = 0, t; i < n; ++i)
{
cin >> t;
++c[t];
}
idx = 0;
memset(h, -1, sizeof h);
for(int i = 0; i < 23; ++i)
{
add(i, i + 1, 0);
add(i + 1, i, -c[i + 1]);
}
for(int i = 0; i < 24; ++i)
add((i + 16) % 24, i, r[i]);
add(23, 0, 0), add(0, 23, -c[0]);
int lo = 1, hi = n + 1;
while(lo < hi)
{
m = lo + hi >> 1;
if(spfa()) lo = m + 1;
else hi = m;
}
if(lo == n + 1) puts("No Solution");
else printf("%d\n", lo);
}
}