【分析】
这题比较难啊。。依然是求最少人数:单源最长路,我仍然转化为单源最短路来求。
嗯。。事实上我把 i加1 了,因为毕竟没有 f[-1]这玩意。。
首先将关系式转化为路径,然后从小到大枚举答案即可。
其实pdf里都讲清楚啦。。我在这貌似也只是打个酱油qwq
【代码】
//poj 1275 Cashier Employment
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define fo(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
vector <int> f[50],ff[50];
vector <int> l[50],ll[50];
int T,n,m,x,y,d,tmp,ans;
int dis[50],r[25],q[50001],t[25],huan[50];
bool vis[50];
inline void copy()
{
fo(i,0,24)
{
ff[i].clear();
ll[i].clear();
x=f[i].size()-1;
fo(j,0,x)
ff[i].push_back(f[i][j]),ll[i].push_back(l[i][j]);
}
}
inline bool spfa()
{
memset(huan,0,sizeof huan);
memset(dis,0x7f,sizeof dis);
memset(vis,0,sizeof vis);
dis[0]=0;
vis[0]=1;
huan[0]++;
int h=0,tt=1;
q[tt]=0;
while(h<tt)
{
int u=q[++h];
vis[u]=0;
int x=ff[u].size()-1;
fo(i,0,x)
{
int v=ff[u][i];
if(dis[v]>dis[u]+ll[u][i])
{
dis[v]=dis[u]+ll[u][i];
if(!vis[v])
vis[v]=1,q[++tt]=v,huan[v]++;
if(huan[v]>25) return 0;
}
}
}
return 1;
}
int main()
{
scanf("%d",&T);
while(T--)
{
fo(i,0,49) f[i].clear(),l[i].clear();
memset(t,0,sizeof t);
memset(r,0,sizeof r);
fo(i,0,49) dis[i]=1000000000;
fo(i,1,24)
scanf("%d",&r[i]);
scanf("%d",&n);
fo(i,1,n)
{
scanf("%d",&x);
t[x+1]++;
}
fo(i,1,24)
f[i-1].push_back(i),l[i-1].push_back(0); //f[i]>=f[i-1]
fo(i,8,24)
f[i-8].push_back(i),l[i-8].push_back(-r[i]); //f[i]-f[i-8]>=r[i]
fo(i,1,24)
f[i].push_back(i-1),l[i].push_back(t[i]); //f[i]-f[i-1]<=t[i]
for(tmp=0;tmp<=n;tmp++)
{
copy();
fo(i,1,7)
ff[i+16].push_back(i),ll[i+16].push_back(tmp-r[i]);
ff[0].push_back(24);
ll[0].push_back(-tmp);
if(spfa()) break;
}
if(tmp<=n) printf("%d\n",tmp);
else printf("No Solution\n");
}
return 0;
}