【网络流24】餐巾
自己没想出来,看题解了QAQ
原题:
某软件公司正在规划一项n天的软件开发计划,根据开发计划第i天需要ni个软件开发人员,为了提高软件开发人员的效率,公司给软件人员提供了很多的服务,其中一项服务就是要为每个开发人员每天提供一块消毒毛巾,这种消毒毛巾使用一天后必须再做消毒处理后才能使用。消毒方式有两种,A种方式的消毒需要a天时间,B种方式的消毒需要b天(b>a),A种消毒方式的费用为每块毛巾fA, B种消毒方式的费用为每块毛巾fB,而买一块新毛巾的费用为f(新毛巾是已消毒的,当天可以使用);而且f>fA>fB。公司经理正在规划在这n天中,每天买多少块新毛巾、每天送多少块毛巾进行A种消毒和每天送多少块毛巾进行B种消毒。当然,公司经理希望费用最低。
你的任务就是:为该软件公司计划每天买多少块毛巾、每天多少块毛巾进行A种消毒和多少毛巾进行B种消毒,使公司在这项n天的软件开发中,提供毛巾服务的总费用最低。
1≤f,fA,fB≤60,1≤n≤1000
最开始的想法是拆点,拆出的两个点中间连需求的边,割掉表示满足需求,右边的点到汇流量无穷费用0,源到左边的点流量无穷费用为买新的的费用表示可以随意买,右边的点到左边标号+a或b的点流量无穷费用为洗的费用表示,搞了大约2h,然后怎么debug都找不出来问题 (ノ`Д′)ノ︵┻━┻
然后跟踪发现这样建图是不对的……因为从右边到左边的流量经理了两个阶段,先买再洗(如果洗多次的话还会更多),所以洗的花费实际上是买+洗的话费,大于直接买的费用,然后就根本不会增广这一条边……
然后发现思路已经转不过来了,想了一段时间无果,然后各种颓,拖到晚上实在不能再拖了就看了题解QAQ
正解是利用每天产生的脏毛巾已经被钦♂定了这一特殊性,拆点,左边表示脏毛巾,右边表示干净的,源到左边流量为需求费用为0表示每天免费产生固定数量的毛巾,然后源到右边流量无穷费用为新买一条的费用表示任意买,脏毛巾到标号+a或b流量无穷费用为清洗一次的费用表示清洗,最后右边的点到汇流量为需求费用为0的来限制流量,割的意义为满足需求
然后闵神和郑州高一神犇stdcall指点,虽然网络流这种东西需要练习,但是自己想的时间太长的话效率会很低,stdcall建议思考时间是0.5-1h
还要提高效率啊……
代码(思路略乱……):
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 int read(){int z=0,mark=1; char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')mark=-1; ch=getchar();} 9 while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();} 10 return z*mark; 11 } 12 const int oo=168430090; 13 struct ddd{int next,y,evalue,rev,cost;}e[1100000]; int LINK[510000],ltop=0; 14 inline void insert(int x,int y,int z,int _cost){ 15 e[++ltop].next=LINK[x];LINK[x]=ltop;e[ltop].y=y;e[ltop].evalue=z;e[ltop].rev=ltop+1;e[ltop].cost=_cost; 16 e[++ltop].next=LINK[y];LINK[y]=ltop;e[ltop].y=x;e[ltop].evalue=0;e[ltop].rev=ltop-1;e[ltop].cost=-_cost; 17 } 18 int n,a,b,ncost,acost,bcost; int S,s,t; 19 int dist[510000]; 20 int QUEUE[510000],head=0; bool visited[510000]; 21 int last[510000],last_e[510000]; 22 bool spfa(){ 23 memset(visited,0,sizeof(visited)); 24 memset(dist,10,sizeof(dist)); 25 QUEUE[head=1]=s; visited[s]=true; dist[s]=0; 26 for(int k=1;k<=head;k++){ 27 for(int i=LINK[QUEUE[k]];i;i=e[i].next) 28 if(e[i].evalue && dist[QUEUE[k]]+e[i].cost<dist[e[i].y]){ 29 dist[e[i].y]=dist[QUEUE[k]]+e[i].cost; 30 last[e[i].y]=QUEUE[k],last_e[e[i].y]=i; 31 if(!visited[e[i].y]) QUEUE[++head]=e[i].y,visited[e[i].y]=true; 32 //cout<<e[i].evalue<<endl; 33 } 34 visited[QUEUE[k]]=false; 35 } 36 return dist[t]<oo; 37 } 38 int cost_flow(){ 39 int bowl=0; 40 while(spfa()){ 41 int min_flow=oo; 42 for(int i=t;i!=s;i=last[i]) min_flow=min(min_flow,e[last_e[i]].evalue); 43 for(int i=t;i!=s;i=last[i]){ 44 bowl+=e[last_e[i]].cost*min_flow; 45 //cout<<last[i]<<"->"<<i<<" "<<e[last_e[i]].cost*min_flow<<endl; 46 e[last_e[i]].evalue-=min_flow,e[e[last_e[i]].rev].evalue+=min_flow; 47 } 48 } 49 return bowl; 50 } 51 int main(){freopen("ddd.in","r",stdin); 52 cin>>n>>a>>b>>ncost>>acost>>bcost; S=n; s=0,t=S<<1; 53 for(int i=1;i<=n;i++) insert(i,S+i,read(),0),insert(S+i,t,oo,0); 54 for(int i=1;i<=n;i++){ 55 insert(s,i,oo,ncost); 56 for(int j=i+a+1;j<=n;j++) insert(S+i,j,oo,acost-ncost); 57 for(int j=i+b+1;j<=n;j++) insert(S+i,j,oo,bcost-ncost); 58 } 59 cout<<cost_flow()<<endl; 60 return 0; 61 }