题解 洛谷P1251 网络流24题.01【餐巾计划问题】
\(\huge\mathbb{DESCRIPTION}\)
编号:洛谷\(P1251\)、\(LOJ6008\)(与洛谷上本题输入顺序有不同)
算法:最小费用最大流、贪心
来源:网络流\(24\)题
\(\huge\mathbb{SOLUTION}\)
这道题目我们可以用最小费用最大流来解决。
首先,我们要考虑如何建图。
我们可以连一下的几类边:
\(Number\) | \(From\) | \(To\) | \(Stream\) | \(Cost\) |
---|---|---|---|---|
1 | 源点\(Start\) | 第\(i\)天的早上 | \(INF\) | \(Buy\) |
2 | 源点\(Start\) | 第\(i\)天的晚上 | \(Should_i\) | \(0\) |
3 | 第\(i\)天的晚上 | 第\(i+1\)天的晚上 | \(INF\) | \(0\) |
4 | 第\(i\)天的晚上 | 第\(i+QuickTime\)天的晚上 | \(INF\) | \(QuickCost\) |
5 | 第\(i\)天的晚上 | 第\(i+SlowTime\)天的晚上 | \(INF\) | \(SlowCost\) |
6 | 第\(i\)天的早上 | 汇点\(End\) | \(Should_i\) | \(0\) |
思路似乎一下子就出来了。 | ||||
建完图以后跑一遍最小费用最大流的模板,一路增广,结果就出来了。 | ||||
\(P.S.\)如果您在洛谷上得到了\(80\)分,可能是没有开\(long long\)的锅\(QωQ\)。 | ||||
\(AC\)链接 | ||||
\(\huge\mathbb{CODE}\) |
#include<bits/stdc++.h>
#define INF 0x7ffffff
#define MAX 10001
using namespace std;
int TotalPoint;
int Start,End;
long long Ans,AllCost;
bool Visit[MAX];
bool VisitDfs[MAX];
long long Dist[MAX];
int Days;
int Should[MAX];
int Buy,QuickTime,QuickCost,SlowTime,SlowCost;
vector<int>Edge[MAX];
vector<int>Stream[MAX];
vector<int>Cost[MAX];
vector<int>Size[MAX];
inline void AddEdge(int From,int To,int NowStream,int NowCost)
{
Edge[From].push_back(To);
Edge[To].push_back(From);
Stream[From].push_back(NowStream);
Stream[To].push_back(0);
Cost[From].push_back(NowCost);
Cost[To].push_back(-NowCost);
Size[From].push_back(Edge[To].size()-1);
Size[To].push_back(Edge[From].size()-1);
}
inline bool Spfa(int Start,int End)
{
register queue<int>Queue;
register int i;
for(i=1;i<=TotalPoint;i++)
{
VisitDfs[i]=false;
Visit[i]=false;
Dist[i]=INF;
}
Visit[Start]=true;
Dist[Start]=0;
Queue.push(Start);
while(!Queue.empty())
{
register int Top;
Top=Queue.front();
Queue.pop();
Visit[Top]=false;
for(i=0;i<Edge[Top].size();i++)
{
register int Next;
Next=Edge[Top][i];
if(Dist[Top]+Cost[Top][i]<Dist[Next]&&Stream[Top][i])
{
Dist[Next]=Dist[Top]+Cost[Top][i];
if(!Visit[Next])
{
Visit[Next]=true;
Queue.push(Next);
}
}
}
}
return Dist[End]!=INF;
}
inline int Dfs(int Now,int End,int Min)
{
if(!Min||Now==End)
{
return Min;
}
register int Return;
Return=0;
VisitDfs[Now]=1;
register int i;
for(i=0;i<Edge[Now].size();i++)
{
register int Next=Edge[Now][i];
if(Dist[Now]+Cost[Now][i]==Dist[Next]&&Stream[Now][i]&&!VisitDfs[Next])
{
register int MinStream;
MinStream=Dfs(Next,End,min(Min,Stream[Now][i]));
Stream[Now][i]-=MinStream;
Stream[Next][Size[Now][i]]+=MinStream;
Min-=MinStream;
Return+=MinStream;
AllCost+=MinStream*Cost[Now][i];
}
}
return Return;
}
inline void Mcmf()
{
while(Spfa(Start,End))
{
Ans+=Dfs(Start,End,INF);
}
}
int main(void)
{
register int i;
cin>>Days;
for(i=1;i<=Days;i++)
{
cin>>Should[i];
}
cin>>Buy>>QuickTime>>QuickCost>>SlowTime>>SlowCost;
Start=0;
End=2*Days+1;
for(i=1;i<=Days;i++)
{
AddEdge(Start,i,Should[i],0);
}
for(i=1;i<=Days;i++)
{
AddEdge(i+Days,End,Should[i],0);
}
for(i=1;i<=Days;i++)
{
if(i+1<=Days)
{
AddEdge(i,i+1,INF,0);
}
if(i+QuickTime<=Days)
{
AddEdge(i,i+QuickTime+Days,INF,QuickCost);
}
if(i+SlowTime<=Days)
{
AddEdge(i,i+SlowTime+Days,INF,SlowCost);
}
AddEdge(0,i+Days,INF,Buy);
}
TotalPoint=2*Days+1;
Mcmf();
cout<<AllCost<<endl;
return 0;
}
不要妄图追上西坠的太阳,而是要在黎明前就等着它!