Shoot the Bullet Time Limit: 2 Seconds Memory Limit: 32768 KB Special Judge
Gensokyo is a world which exists quietly beside ours, separated by a mystical border. It is a utopia where humans and other beings such as fairies, youkai(phantoms), and gods live peacefully together. Shameimaru Aya is a crow tengu with the ability to manipulate wind who has been in Gensokyo for over 1000 years. She runs the Bunbunmaru News - a newspaper chock-full of rumors, and owns the Bunkachou - her record of interesting observations for Bunbunmaru News articles and pictures of beautiful danmaku(barrange) or cute girls living in Gensokyo. She is the biggest connoisseur of rumors about the girls of Gensokyo among the tengu. Her intelligence gathering abilities are the best in Gensokyo!
During the coming n days, Aya is planning to take many photos of m cute girls living in Gensokyo to write Bunbunmaru News daily and record at least Gx photos of girl x in total in the Bunkachou. At the k-th day, there are Ck targets, Tk1, Tk2, ..., TkCk. The number of photos of target Tki that Aya takes should be in range [Lki, Rki], if less, Aya cannot write an interesting article, if more, the girl will become angry and use her last spell card to attack Aya. What's more, Aya cannot take more than Dk photos at the k-th day. Under these constraints, the more photos, the better.
Aya is not good at solving this complex problem. So she comes to you, an earthling, for help.
Input
There are about 40 cases. Process to the end of file.
Each case begins with two integers 1 <= n <= 365, 1 <= m <= 1000. Then m integers, G1, G2, ..., Gm in range [0, 10000]. Then n days. Each day begins with two integer 1 <= C <= 100, 0 <= D <= 30000. Then C different targets. Each target is described by three integers, 0 <= T < m, 0 <= L <= R <= 100.
Output
For each case, first output the number of photos Aya can take, -1 if it's impossible to satisfy her needing. If there is a best strategy, output the number of photos of each girl Aya should take at each day on separate lines. The output must be in the same order as the input. If there are more than one best strategy, any one will be OK.
Output a blank line after each case.
Sample Input
2 3 12 12 12 3 18 0 3 9 1 3 9 2 3 9 3 18 0 3 9 1 3 9 2 3 9 2 3 12 12 12 3 18 0 3 9 1 3 9 2 3 9 3 18 0 0 3 1 3 6 2 6 9 2 3 12 12 12 3 15 0 3 9 1 3 9 2 3 9 3 21 0 0 3 1 3 6 2 6 12
Sample Output
36 6 6 6 6 6 6 36 9 6 3 3 6 9 -1
External Links
Author: WU, Zejun
Source: ZOJ Monthly, July 2009
题意:用n天对m个girls进行拍照,每个girl有总共的拍照次数下限
每天有拍照次数上限。
第i天可以对k个girls拍照,对每个girl有拍照次数下限和上限。
求最大拍照次数。
算法:
1.先转化为有源汇上下界可行流问题来求解一个可行流。若可行无解,则退出。由于必要弧是分离出来的,所以就可以把必要弧(附加源汇及其临边)及其上的流,暂时删去。再将(T,S)删去,恢复源汇。
2.从S到T找增广轨,求最大流。从T到S找增广轨,不断反着改进,求最小流。
3.最后将暂时删去的下界信息恢复,合并到当前图中。输出解。
有源汇上下界网络流的另一种简易求法:
注意问题[2](有源汇可行流)中,构造出的(t, s),上下界几乎没什么限制。下面看看它的性质:
定理:如果从s到t有一个流量为a的可行流f,那么从t到s连一条弧(t, s),其流量下界b(t, s) = a,则这个图一定有一个无源汇的可行流:除了弧(t, s)的容量为a外,其余边的容量与f相同。
可以二分枚举这个参数a,即下界b(t, s),每次用问题[1](无源汇可行流)判断是否有可行流。这样就可以求出最大流。要求最小流,只要二分枚举上界c(t, s)即可。
------------------------------------
二分超时...
代码:
#include<cstdio> #include<cstring> #include<algorithm> #define N 1500 #define inf 999999999 using namespace std; int n,m,s,t,num,adj[N],dis[N],q[N]; int B[366][1005],in[N],out[N],stk[1005],top; struct edge { int v,w,pre; edge(){} edge(int vv,int ww,int p){v=vv;w=ww;pre=p;} }e[100005]; void insert(int u,int v,int w) { e[num]=edge(v,w,adj[u]); adj[u]=num++; e[num]=edge(u,0,adj[v]); adj[v]=num++; } int bfs() { int i,x,v,head=0,tail=0; memset(dis,0,sizeof(dis)); dis[s]=1; q[++tail]=s; while(head!=tail) { x=q[head=(head+1)%N]; for(i=adj[x];~i;i=e[i].pre) if(e[i].w&&!dis[v=e[i].v]) { dis[v]=dis[x]+1; if(v==t) return 1; q[tail=(tail+1)%N]=v; } } return 0; } int dfs(int x,int limit) { if(x==t) return limit; int i,v,tmp,cost=0; for(i=adj[x];~i&&cost<limit;i=e[i].pre) if(e[i].w&&dis[x]==dis[v=e[i].v]-1) { tmp=dfs(v,min(limit-cost,e[i].w)); if(tmp) { e[i].w-=tmp; e[i^1].w+=tmp; cost+=tmp; } else dis[v]=-1; } return cost; } int Dinic() { int ans=0; while(bfs()) ans+=dfs(s,inf); return ans; } int main() { while(~scanf("%d%d",&n,&m)) { int i,j,k,w,b,S,T,ans,sum=0; memset(adj,-1,sizeof(adj)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); num=0; S=0; T=n+m+1; insert(T,S,inf); for(i=1;i<=m;i++) { scanf("%d",&w); insert(n+i,T,inf-w); in[T]+=w; out[n+i]+=w; } for(i=1;i<=n;i++) { scanf("%d%d",&k,&w); insert(S,i,w); while(k--) { scanf("%d%d%d",&j,&b,&w); B[i][++j]=b; insert(i,n+j,w-b); in[n+j]+=b; out[i]+=b; } } s=T+1; t=s+1; for(i=S;i<=T;i++) { if(in[i]>out[i]) { sum+=in[i]-out[i]; insert(s,i,in[i]-out[i]); } if(in[i]<out[i]) insert(i,t,out[i]-in[i]); } ans=Dinic(); if(ans!=sum) { puts("-1\n"); continue; } e[0].w=e[1].w=0; for(i=adj[s];~i;i=e[i].pre) e[i].w=e[i^1].w=0; for(i=adj[t];~i;i=e[i].pre) e[i].w=e[i^1].w=0; s=S; t=T; printf("%d\n",ans+Dinic()); for(i=1;i<=n;i++) { top=0; for(j=adj[i];~j;j=e[j].pre) if(e[j].v>n&&e[j].v<=n+m) stk[++top]=e[j^1].w+B[i][e[j].v-n]; while(top) printf("%d\n",stk[top--]); } puts(""); } }