【网络流24题】餐巾计划问题

题目:

https://www.luogu.org/problemnew/show/P1251

题解:

原来的想法不行:算费用的时候算的是一条餐巾的,但对于重复使用多天的餐巾不公平,因为他们的费用肯定比用一次的大,但是它们贡献也大。

两种想法:

->平均费用 不可做。

->这一次费用 可做。

嘿嘿,还挺有意思的。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
#include<cstdlib>
#define LL long long
#define N 10000
#define INF 1000000007
#define S 0
#define T (2*n+1)
#define ri register int
using namespace std;

int n,cc;
int r[N],p0,t1,p1,t2,p2;

int cr(int x){
  return 2*n+x+1;
}

struct graph {
  vector<int> to,w,c;
  vector<int> ed[N];
  LL dis[N]; int cur[N];
  bool vis[N];
  
  void add_edge(int a,int b,int aw,int ac) {
    to.push_back(b); w.push_back(aw); c.push_back(ac);  ed[a].push_back(to.size()-1);
    to.push_back(a); w.push_back(0);  c.push_back(-ac); ed[b].push_back(to.size()-1);
  }
  
  bool spfa() {
    memset(dis,0x2f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    queue<int> q;
    dis[S]=0;q.push(S);vis[S]=1;
    while (!q.empty()) {
      int x=q.front(); q.pop();
      //printf("%d %d %lld\n",cc,x,dis[x]);
      for (ri i=0;i<ed[x].size();i++) {
        int e=ed[x][i];
        if (dis[to[e]]>dis[x]+c[e] && w[e]) {
          dis[to[e]]=dis[x]+c[e];
          if (!vis[to[e]]) vis[to[e]]=1,q.push(to[e]);
        }
      }
      vis[x]=0;
    }
    return dis[T]<INF;
  }
  int dfs(int x,int lim) {
    if (x==T || !lim) return lim;
    LL sum=0; vis[x]=1;
    for (ri &i=cur[x];i<ed[x].size();i++) {
      int e=ed[x][i];
      if (dis[x]+c[e]==dis[to[e]] && w[e] && !vis[to[e]]) {
        int f=dfs(to[e],min(lim,w[e]));
        w[e]-=f; w[1^e]+=f;
        lim-=f; sum+=f;
        if (!lim) return sum;
      }
    }
    return sum;
  }
  LL zkw() {
    LL ret=0;
    cc=1;
    while (spfa()) {
      memset(vis,0,sizeof(vis));
      memset(cur,0,sizeof(cur));
      int t=dfs(S,INF);
      ++cc;
      ret+=t*dis[T];
    }
    return ret;
  }
} G;

int main() {
  scanf("%d",&n);
  for (ri i=1;i<=n;i++) scanf("%d",&r[i]);
  scanf("%d %d %d %d %d",&p0,&t1,&p1,&t2,&p2);
  for (ri i=1;i<=n;i++) G.add_edge(S,n+i,r[i],0);
  for (ri i=1;i<=n;i++) G.add_edge(i,T,r[i],0);
  for (ri i=1;i<n;i++)  G.add_edge(n+i,n+i+1,INF,0);
  for (ri i=1;i<=n;i++) {
    if (i+t1<=n) G.add_edge(n+i,i+t1,INF,p1);
    if (i+t2<=n) G.add_edge(n+i,i+t2,INF,p2);
  }
  for (ri i=1;i<=n;i++) G.add_edge(S,i,INF,p0);
  printf("%lld\n",G.zkw());
  return 0;
}
posted @ 2019-07-12 19:51  HellPix  阅读(274)  评论(0编辑  收藏  举报