餐巾计划问题

这个题非常的好,真的......我半颓半打,打了一下午最后还是去看了题解,,,,

这个题对限制条件的转换非常的好

先贴代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 long long tot=-1,sum=0,h[10005],flow[10005],g[10005],ans=0,dis[10005],ans2=0,inf=999999;
 5 bool vis[10005];
 6 struct node{
 7     long long from,to,next,rest,cost;
 8 }e[10000005];
 9 
10 void add(long long x,long long y,long long z,long long hg){
11     tot++;
12     e[tot].next=h[x];
13     h[x]=tot;
14     e[tot].cost=hg;
15     e[tot].from=x;
16     e[tot].to=y;
17     e[tot].rest=z;
18 }
19 
20 int bfs(long long s,long long t){
21     queue<int>q;
22     q.push(s);dis[s]=0;vis[s]=true;
23     while(!q.empty()){
24         long long u=q.front();q.pop();vis[u]=false;
25         for(int i=h[u];i!=(-1);i=e[i].next){
26             if(e[i].rest>0&&dis[e[i].to]>dis[u]+e[i].cost){
27                 flow[e[i].to]=min(flow[u],e[i].rest);
28                 dis[e[i].to]=dis[u]+e[i].cost;
29                 g[e[i].to]=i;
30                 if(vis[e[i].to]==false)q.push(e[i].to),vis[e[i].to]=true;
31             }
32         }
33     }
34 }
35 
36 int EK(long long s,long long t){
37     while(1){
38         memset(flow,0x7f,sizeof(flow));
39         memset(dis,0x7f,sizeof(dis));
40         memset(g,-1,sizeof(g));
41         memset(vis,false,sizeof(vis));
42         bfs(s,t);
43         if(g[t]!=(-1)){
44             ans+=flow[t];ans2+=dis[t]*flow[t];
45             for(int p=t;p!=s;p=e[g[p]].from){
46                 e[g[p]].rest-=flow[t];
47                 e[g[p]^1].rest+=flow[t];
48             }
49         }
50         else break; 
51     }
52 }
53 
54 int n,P,m,f,N,S,r;
55 
56 int main(){
57     memset(h,-1,sizeof(h));
58     cin>>n>>P>>m>>f>>N>>S;
59     for(int i=1;i<=n;i++){
60         cin>>r;
61         add(0,i,r,0);
62         add(i,0,0,0);
63         add(i+n,2*n+1,r,0);
64         add(2*n+1,i+n,0,0);
65         add(0,i+n,inf,P);
66         add(i+n,0,0,-P);
67         if(i+m<=n)add(i,i+m+n,inf,f),add(i+m+n,i,0,-f);
68         if(i+N<=n)add(i,i+N+n,inf,S),add(i+N+n,i,0,-S);
69         if(i<n)add(i,i+1,inf,0),add(i+1,i,0,0);
70     }
71     EK(0,2*n+1);
72     cout<<ans2<<endl;
73 }
......我太菜了

我原本做这个题的时候,本来是这么想的

1.把节点分为用了和没用,俩俩连边

2.对于买,直接现在1号节点买好(因为后面什么时候买可以),就把源点连1号,同理汇点连n号用过的...

3.对于洗,就把用了的连多少天之后.....

4.然后在上面跑费用流就好了....

5.没用的之间俩俩连边....

但是错了.....  

分析了一下,错的原因可能是因为求费用流的同时,通过先前节点走到哪里,比从源点直接到那个点的值大得多.....

那我又想了一下,直接处理一下洗衣服的边权不就可以了嘛.....因为对于洗衣服,相当于少付了这么多

但这东西就很怪.....

想不懂为什么wa了.....

可能是因为下面那条边,就是原本买多了的新衣服有路给过去了.......然后又因为求的是最大流.....

诶,那我把买多了的新衣服去掉,只有剩下的旧衣服会怎么样??,,图就不连通了

....

立个flag,谁用我上面的方法做出来我请你吃饭

好吧,向正解低头

嘛,正解用到了一个引理,就是每天一定能得到要求的衣服,只是途径不同,,,,,

那很好办了.

直接建立两种节点,有和没有用过的.....

然后对于用过的可以根据洗衣服的规则到这么多天的没有用过的....

然后买也可以解决,没用过的可以由买回来转移得到,于是可以把没用过与(与用掉的相连的源点粘接,代表经过买的连接)...

我在说什么....

嘛真的不推荐你们看这篇题解,太垃圾了....

反正啦,(绯红华尔兹好好听)

反正从这题得出了几个经验

1,不要边颓边学

2.要大力猜想题目条件,不能被局限在原有知识里

3.显然的东西就要大力去用

4.不要抄模板,多打一下多好

.

.

.

原文地址:https://www.cnblogs.com/shatianming/p/12222836.html