[NOIP2009] 最优贸易 (最短路,分层图)

题目链接


Solution

分层图+\(SPFA\)
建立3层图,其中每一层之中的边权赋为0.
对于任意一条边 \(t\) ,其起点 \(x\) 和终点 \(y\).
我们将 \(x\) 在第一层的节点连向 \(y\) 的第二层节点,边权为 \(w[x]\).
代表在 \(x\) 买了这个东西.
然后将 \(x\) 在第二层的节点连向 \(y\) 的第三层节点,边权为 \(-w[x]\).
代表在 \(x\) 卖了这个东西.

此外,囿于可以直接不买不卖,所以直接从节点 \(1\) 连一条边权为 \(0\) 的边向超级终点 \(T\).

然后跑 \(SPFA\) . 注意,一般\(dijkstra\)不能跑带负权的图!!!


Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=200008;
struct sj{
	int to,next,w;
}a[maxn*4];
int head[maxn],size;

int read()
{
	char ch=getchar(); int f=1,w=0;
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){w=w*10+ch-'0';ch=getchar();}
	return f*w;
}

void add(int x,int y,int w)
{
	a[++size].to=y;
	a[size].next=head[x];
	head[x]=size;
	a[size].w=w;
}
int n,m,w[maxn];
int dis[maxn],v[maxn];

void spfa()
{
	queue<int>q;
	memset(dis,127,sizeof(dis));
	q.push(1);
	v[1]=1; dis[1]=0;
	while(q.empty()!=1)
	{
		int x=q.front(); q.pop(); v[x]=0;
		for(int i=head[x];i;i=a[i].next)
		{
			int tt=a[i].to;
			if(dis[tt]>dis[x]+a[i].w)
			{
				dis[tt]=dis[x]+a[i].w;
				if(!v[tt])
				q.push(tt),v[tt]=1;
			}			
		}
	}	
}

void pre(int x,int y)
{
	add(x,y,0);
	add(x,y+n,w[x]);
	add(x+n,y+n,0);
	add(x+n,y+2*n,-w[x]);
	add(x+2*n,y+2*n,0);	
}
int main()
{
	n=read(); m=read();
	for(int i=1;i<=n;i++)
	w[i]=read();
	for(int i=1;i<=m;i++)
	{
		int x=read(),y=read(),opt=read();
		pre(x,y);
		if(opt==2)pre(y,x);
	}
	add(1,3*n+1,0);
	add(3*n+1,3*n+2,0);
	add(3*n,3*n+2,0);
	spfa();
	cout<<-1*dis[3*n+2]<<endl;
}
posted @ 2018-08-23 19:59  Kevin_naticl  阅读(214)  评论(0编辑  收藏  举报