题意:一共n天,每天需要p[i]个人,开始只有k个人,每个人只会工作一天,有m个休假方法使工作了的人Tj天后继续工作,但是要付Sj的费用。在第P天以后可以花费Q雇佣新人。问每天的人都是充足的最低费用。
分析:
先在将每个点拆成工作前(xi)工作后(yi)两点。
不考虑休假方式:
s到y1连容量为k费用0的边,
yi到t连容量为p[i]费用为0的边,
yi到yi+1连容量为INF费用为0的边,
第P个点以后连s到yi容量为INF费用为Q的边。
考虑休假方式:
s到xi连容量为p[i]费用为0的边 表示每天能够过休假的人,
xi到yi+tj连容量为INF费用为sj的边 表示休假后继续工作。
最后判断是否满流。
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<queue> #include<cmath> #include<stack> #include<set> #include<map> #define INF 0x3f3f3f3f #define Mn 2005 #define Mm 200005 #define mod 1000000007 #define CLR(a,b) memset((a),(b),sizeof((a))) #define CPY(a,b) memcpy ((a), (b), sizeof((a))) #pragma comment(linker, "/STACK:102400000,102400000") #define ul u<<1 #define ur (u<<1)|1 using namespace std; typedef long long ll; int read() { char c=getchar(); int re=0,f=1; while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') {re=re*10+c-'0';c=getchar();} return re*f; } int dis[Mn],pre[Mn],head[Mn]; bool vis[Mn]; int tot,ans,mflow; struct edge { int v,cap,next,cost; } e[Mm]; void addedge(int u,int v,int w,int cost) { e[tot].v=v; e[tot].cap=w; e[tot].cost=cost; e[tot].next=head[u]; head[u]=tot++; e[tot].v=u; e[tot].cap=0; e[tot].cost=-cost; e[tot].next=head[v]; head[v]=tot++; } queue<int>q; bool spfa(int s,int en) { while(!q.empty()) q.pop(); for(int i=s ; i<=en; i++) { dis[i]=INF; vis[i]=false; pre[i]=-1; } q.push(s); dis[s]=0; vis[s]=true; while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=false; for(int i=head[u]; i!=-1; i=e[i].next) { int v=e[i].v; int cost=e[i].cost; if(e[i].cap&&dis[v]>dis[u]+cost) { dis[v]=dis[u]+cost; pre[v]=i; if(!vis[v]) { vis[v]=true; q.push(v); } } } } if(dis[en]==INF) return false; return true; } void addmaxflow(int t) { int maxflow=INF; for(int i=pre[t]; i!=-1; i=pre[e[i^1].v]) maxflow=min(maxflow,e[i].cap); for(int i=pre[t]; i!=-1; i=pre[e[i^1].v]) { e[i].cap-=maxflow; e[i^1].cap+=maxflow; } ans+=dis[t]*maxflow; mflow+=maxflow; } void get(int s,int t) { while(spfa(s,t)) addmaxflow(t); } void init() { tot=0;ans=0,mflow=0; CLR(head,-1); } int p[Mn]; int a[6],b[5]; int main() { int T=read(); while(T--) { init(); int n=read(),k=read(); int sum=0,s=0,t=2*n+1; for(int i=1;i<=n;i++) { p[i]=read(); sum+=p[i]; addedge(s,i,p[i],0); addedge(i+n,t,p[i],0); } int m=read(),P=read(),Q=read(); for(int i=1;i<=m;i++) { a[i]=read(),b[i]=read(); } addedge(s,1+n,k,0); for(int i=P;i<=n;i++) addedge(s,i+n,INF,Q); //for(int i=1;i<n;i++) addedge(i,i+1,INF,0); for(int i=n+1;i<2*n;i++) addedge(i,i+1,INF,0); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(i+b[j]<=n) addedge(i,i+n+b[j],INF,a[j]); } } get(s,t); if(mflow==sum) cout<<ans<<endl; else cout<<"No solution"<<endl; } return 0; }