洛谷 P1251 餐巾计划问题 解题报告
网络流24题练习。
一开始看到题目,觉得挺简单。
然后在如何处理 " 一天用完的脏毛巾洗完后转移到后面的天数 " 时卡住了。
思路是这样的:
- 将每一天拆成早晚两个点,分开处理脏/新毛巾。(用i表示早上,i+n表示晚上,ai表示每天需要的毛巾)
- s -> i+n连容量为ai的边,表示这一天晚上得到了ai条脏毛巾。
- i -> t 连容量为ai的边,表示每天早上提供ai条新毛巾。
- i+n -> i+n+1,容量inf,表示脏毛巾留到了下一天晚上。
- i+n -> i+d1,容量inf,费用c1,表示脏毛巾送到快洗店,第i+d1天早上洗好了。
- i+n -> i+d2,容量inf,费用c2,表示脏毛巾送到慢洗店,第i+d2天早上洗好了。
- s -> i ,容量inf,费用=买新毛巾的费用,表示每一天可以买新毛巾。
建完图dinic走一波。注意开long long。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <queue> #define ll long long #define space putchar(' ') #define endl putchar('\n') #define debug puts("------------------------") #define F(i,x,n) for(int i=x;i<=n;++i) #define F_(i,x,n) for(int i=x;i>=n;--i) using namespace std; inline void read(int &a) {a=0;int c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b; } inline int Rem() {int a=0,c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();return a*=b; } inline void write(int x) {if(x>9)write(x/10);putchar('0'+x%10);} inline void W(int x) {if(x<0){putchar('-'),x=-x;}write(x);} /**/ const int N=4005,inf=0x3f3f3f3f; const ll INF=(ll)(0x3f3f3f3f3f3f3f3f); int n,s,t,x,head[N],cur[N],cnt=1; ll dis[N],mincost; int buy,c1,d1,c2,d2; bool vis[N]; struct edge { int nxt,to,c,w; }e[N*100]; /**/ namespace DINIC { inline int get(int i,int j,int p=0) { return (i-1)*n + j + n*n*p; } inline void addone(int u,int v,int c,int w) { e[++cnt]=(edge){head[u],v,c,w}; head[u]=cnt; } inline void add(int u,int v,int c,int w) { addone(u,v,c,w); addone(v,u,0,-w); } inline int bfs() { memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); memcpy(cur,head,sizeof(head)); vis[s]=1,dis[s]=0; queue<int>q; q.push(s); while(!q.empty()) { int u=q.front();q.pop();vis[u]=0; for(int i=head[u];i;i=e[i].nxt) { int v=e[i].to; if(dis[v]>dis[u]+e[i].w&&e[i].c) { dis[v]=dis[u]+e[i].w; if(!vis[v]) { vis[v]=1; q.push(v); } } } } return dis[t]!=INF; } int dfs(int u,int flow) { if(u==t) { vis[t]=1; return flow; } vis[u]=1; int used=0,minflow=0; for(int i=head[u];i;i=e[i].nxt) { int v=e[i].to; if((!vis[v]||v==t)&&dis[v]==dis[u]+e[i].w&&e[i].c) { if((minflow=dfs(v,min(flow-used,e[i].c)))!=0) { used+=minflow; e[i].c-=minflow; e[i^1].c+=minflow; mincost+=e[i].w*minflow; if(used==flow) break; } } } return used; } ll Dinic() { while(bfs()) { vis[t]=1; while(vis[t]) { memset(vis,0,sizeof(vis)); dfs(s,inf); } } return mincost; } }using namespace DINIC; int main() { read(n);s=n+n+1,t=s+1; for(int i=1,x;i<=n;i++) { read(x); add(s,i+n,x,0); add(i,t,x,0); } read(buy);read(d1);read(c1);read(d2);read(c2); for(int i=1;i<=n;i++) { add(i+n,i+n+1,inf,0); if(i+d1<=n) add(i+n,i+d1,inf,c1); if(i+d2<=n) add(i+n,i+d2,inf,c2); add(s,i,inf,buy); } cout<<Dinic(); }