https://www.luogu.org/blog/user15019/solution-p1073
这个题使用分层图状态转移来解决的思想如上,不过个人觉得可能那种建图方式有些繁琐,所以出了个写了个简化版本。
我们没有必要把1-n个城市的买入卖出收益存入数组里,在循环里设一个临时变量,然后建图时,将i和i+n相连赋权值,而不用按照第一层的图在第二层找到对应的点,只用竖直下去就可以,这样在跑spfa时会方便许多。注意设一个最终的终点为3*n+1,spfa的数值不要写错,应当是3*n+1就行了
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
const int maxn=100010;
const int maxm=500050;
int head[maxn*3],nnext[maxm*3*2],to[maxm*3*2],length[maxn*3*2];
bool b[maxn*3];
int team[maxn*3],dis[maxn*3],s=0,t=0;
int n,m,tot,sn;
void add(int x,int y,int l)
{
tot++;
nnext[tot]=head[x];
head[x]=tot;
to[tot]=y;
length[tot]=l;
}
void spfa()
{
for(int i=1;i<=sn;i++)
{
dis[i]=-1e9;
}dis[1]=0;
team[t]=1;
t++;
b[1]=true;
while(s!=t)
{
int now=team[s];
s++;
s%=sn;
b[now]=false;
for(int i=head[now];i;i=nnext[i])
{
int y=to[i];
if(dis[y]<dis[now]+length[i])
{
dis[y]=dis[now]+length[i];
if(b[y]==false)
{
team[t]=y;
t++;
t%=sn;
b[y]=true;
}
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int tmp;
cin>>tmp;
add(i,i+n,-tmp);
add(i+n,i+2*n,tmp);
}
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
add(x,y,0);
x+=n,y+=n;add(x,y,0);
x+=n,y+=n;add(x,y,0);
if(z==2)
{
add(y,x,0);
x-=n,y-=n;add(y,x,0);
x-=n,y-=n;add(y,x,0);
}
}
sn=3*n+1;
add(n,3*n+1,0);
add(3*n,3*n+1,0);
spfa();
cout<<dis[sn]<<endl;
return 0;
}