[关闭]
@ysner 2018-08-13T16:23:02.000000Z 字数 3762 阅读 2002

团圆

网络流


题面

个站台,每个站台距第一个站台的距离为公里。一列火车,上有个座位。位乘客,乘坐火车区间为
设代价为每公里火车上空置座位数之和。
最小化代价,并最大化乘车人数。
(输出代价占、最大人数乘车方案占、怎样安排都有车坐的人占

解析

算法

大力即可。
不过这个看起来好神仙。

记得一位只占字节。

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. #define rg register
  4. using namespace std;
  5. const int MAXN=3510;
  6. struct gao{ int Le,Ri; }App[MAXN];
  7. struct zhang{ int Maxs; bitset<MAXN>Tra,Mst; }Ans;
  8. int n,k,q,A[MAXN],Maxv;
  9. struct yi{
  10. zhang Dp[MAXN]; int First[MAXN],Next[MAXN];
  11. inline void Solve()
  12. { for(rg int i=0;i<=n;i++) First[i]=-1;
  13. for(rg int i=1;i<=n;i++) A[i]+=A[i-1];
  14. for(rg int i=1;i<=q;i++)
  15. Next[i]=First[App[i].Ri],First[App[i].Ri]=i;
  16. for(rg int i=1;i<=n;i++)
  17. { Dp[i]=Dp[i-1];
  18. for(rg int j=First[i];j!=-1;j=Next[j])
  19. { zhang Now=Dp[App[j].Le]; Now.Tra[j]=1,Now.Mst[j]=1;
  20. Now.Maxs+=A[App[j].Ri]-A[App[j].Le];
  21. if(Now.Maxs<Dp[i].Maxs) continue ;
  22. if(Now.Maxs==Dp[i].Maxs&&Now.Tra.count()<Dp[i].Tra.count()) continue ;
  23. if(Now.Maxs>Dp[i].Maxs||Now.Tra.count()>Dp[i].Tra.count()) Dp[i]=Now;
  24. Dp[i].Mst&=Now.Mst;
  25. }
  26. }
  27. printf("%d\n",Maxv-Dp[n].Maxs);
  28. for(rg int i=1;i<=q;i++) putchar(Dp[n].Tra[i]?'Y':'N');
  29. printf("\n%d\n",(int)Dp[n].Mst.count());
  30. for(rg int i=1;i<=q;i++) if(Dp[n].Mst[i]) printf("%d ",i);
  31. printf("(%d %d)\n",Dp[2].Maxs,(int)Dp[2].Tra.count());
  32. }
  33. }TP2;
  34. int main()
  35. {
  36. n=Read(); k=Read();
  37. for(rg int i=2;i<=n;i++) A[i]=Read();
  38. for(rg int i=n;i>=2;i--) A[i]-=A[i-1],Maxv+=A[i]*k;
  39. q=Read();
  40. for(rg int i=1;i<=q;i++)
  41. App[i].Le=Read(),App[i].Ri=Read();
  42. if(k==1) TP2.Solve();
  43. }

算法

首先这是一个网络流经典模型。
应在各个站台间连容量为,费用为的边,然后各个区间两端连容量为,费用为的边(看作两种不同的选择)。
跑最大费用最大流即可。

跑最大费用与最小费用的区别是,数组初值置为,然后每次把数组往上更新。
乘车的乘客就是满流的、容量减为的带费用边所代表的乘客。

算法

注意到有一种套路,如果要同时最小化或最大化两个量,则等价于最小化或最大化
但是,必须大到足以区分。一般来说,

在当前题目中,对应代价,对应乘车人数。
于是把带费用边的费用改为即可。

算法

针对每个乘客的区间,可以在残量网络上跑一跑最大费用最大流(即找一找有没有不走当前乘客区间的、收益相同的方案)。
若该区间内,收益仍然等于该区间带费用边的费用,就说明不一定要走一开始用的带费用边,且方案仍最优;即可不选该乘客。
反之必选。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<queue>
  8. #define re register
  9. #define il inline
  10. #define ll long long
  11. #define max(a,b) ((a)>(b)?(a):(b))
  12. #define min(a,b) ((a)<(b)?(a):(b))
  13. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  14. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  15. using namespace std;
  16. const int mod=1e9+7,N=8005,inf=1e9,M=1e6;
  17. struct Edge{int to,nxt,w;ll c;}e[N*100];
  18. struct data{int l,r;}a[N];
  19. int n,k,h[N],cnt=1,q,S,T,pv[N],pe[N],gu[N],p[N],top,sta[N];
  20. ll dis[N],ans;
  21. bool vis[N];
  22. queue<int>Q;
  23. il void add(re int u,re int v,re int w,re ll c)
  24. {
  25. e[++cnt].to=v;e[cnt].nxt=h[u];e[cnt].w=w;e[cnt].c=c;h[u]=cnt;
  26. e[++cnt].to=u;e[cnt].nxt=h[v];e[cnt].w=0;e[cnt].c=-c;h[v]=cnt;
  27. }
  28. il ll gi()
  29. {
  30. re ll x=0,t=1;
  31. re char ch=getchar();
  32. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  33. if(ch=='-') t=-1,ch=getchar();
  34. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  35. return x*t;
  36. }
  37. il int SPFA(re int S)
  38. {
  39. memset(dis,-63,sizeof(dis));dis[S]=0;vis[S]=1;Q.push(S);
  40. while(!Q.empty())
  41. {
  42. re int u=Q.front();Q.pop();
  43. for(re int i=h[u];i+1;i=e[i].nxt)
  44. {
  45. re int v=e[i].to;
  46. if(e[i].w&&dis[v]<dis[u]+e[i].c)
  47. {
  48. dis[v]=dis[u]+e[i].c;
  49. pe[v]=i;pv[v]=u;
  50. if(!vis[v]) vis[v]=1,Q.push(v);
  51. }
  52. }
  53. vis[u]=0;
  54. }
  55. return dis[T]>dis[0];
  56. }
  57. int main()
  58. {
  59. freopen("reunion.in","r",stdin);
  60. freopen("reunion.out","w",stdout);
  61. memset(h,-1,sizeof(h));
  62. n=gi();k=gi();S=n+1;T=S+1;
  63. fp(i,2,n) p[i]=gi();
  64. q=gi();
  65. fp(i,1,q) a[i].l=gi(),a[i].r=gi(),add(a[i].l,a[i].r,1,(p[a[i].r]-p[a[i].l])*M+1),gu[i]=cnt-1;
  66. add(S,1,k,0);fp(i,1,n-1) add(i,i+1,k,0);add(n,T,k,0);
  67. while(SPFA(S))
  68. {
  69. re ll sum=1e18;
  70. for(re int i=T;i!=S;i=pv[i]) sum=min(sum,e[pe[i]].w);
  71. for(re int i=T;i!=S;i=pv[i]) e[pe[i]].w-=sum,e[pe[i]^1].w+=sum;
  72. ans+=sum*dis[T];
  73. }
  74. printf("%lld\n",p[n]*k-ans/M);
  75. fp(i,1,q) if(e[gu[i]].w) putchar('N');else putchar('Y');puts("");
  76. fp(i,1,q)
  77. {
  78. if(e[gu[i]].w) continue;
  79. SPFA(a[i].l);
  80. if(dis[a[i].r]<(p[a[i].r]-p[a[i].l])*M+1) sta[++top]=i;
  81. }
  82. printf("%d\n",top);
  83. fp(i,1,top) printf("%d ",sta[i]);puts("");
  84. fclose(stdin);
  85. fclose(stdout);
  86. return 0;
  87. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注