「JOI 2018 Final」月票购买

JOI 所住的城市有 N 个车站,分别编号为 1::N。有 M条铁路,编号为 1..M。第I 条铁路双向连接车站 A 与车站 B,乘车费用为 C。

JOI 住在车站 S 附近,而 JOI 所在的 IOI 高中在车站 T 附近。他打算买一张月票往返这两个车站。当他买这张月票时,他需要选择一条在车站 S 与车站 T之间的乘车费用最小的路径。有了这张月票,JOI 可以无需额外费用,双向通过任意所选路径包含的铁路。

JOI 经常去在车站 U 与车站 V 附近的书店,因此他希望能买一张月票使得从车站 U 到车站 V 的花费最小。

当他要从车站 U 去往车站 V 时,他会选择一条从车站 U 到车站 V 的路径。对于路径上的每段铁路,如果这段铁路在月票指定的路径范围内,则费用为 0 ,否则费用为C 。每段铁路的费用和为 JOI 从车站 U 到车站 V 的总费用。

他想要知道,如果他买月票时选择了一条合适的路线,从车站 U到车站 V 的最小费用是多少。

你需要编写一个程序计算最小费用。

解:
真是一道好题目啊
首先我们有一个贪心策略 首先将所有最短路上的边设置为有向边 然后再跑最短路 但是这样做有问题 因为两条路可能在两条最短路上 这就很难受了
但是!!! 注意到 这是一条连续的路径 最短路的边一定是DAG DAG上搞事情 DP啊 最短路的题目 不是建立图就是考DP 想DP 而且是一个在最短路上搞的DP 注意到 题目的条件是在一条最短路上 而一条最短路的条件为 \(dis[u]==dis[v]+le[i]\)然后我们就可以DP了 在图上的DP一定是在一个top序列上DP 于是我们就想到了 将最短路作为top序列进行DP 具体实现可以利用\(dij\)来做

topp序列DAG DP

queue<int> q;
void DP() {
    for (int i = 1; i <= n; fu[i] = vu[i], fv[i] = vv[i], i++)
        if (!deg[i])
            q.push(i);
    while (q.size()) {
        int x = q.front();
        q.pop();
        ans = min(ans, min(fv[x] + vu[x], fu[x] + vv[x]));
        for (int i = las[x]; i; i = pre[i]) {
            int y = to[i];
            fu[y] = min(fu[y], fu[x]), fv[y] = min(fv[y], fv[x]);
            if (--deg[y] == 0)
                q.push(y);
        }
    }
}

code:

//
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define inf (ll)(1e17)
#define maxnn 2010000
ll las[maxnn],nex[maxnn],le[maxnn],tot,en[maxnn];

ll zlas[maxnn],znex[maxnn],zle[maxnn],ztot,zen[maxnn];
ll flas[maxnn],fnex[maxnn],fle[maxnn],ftot;
ll dis1[maxnn],dis2[maxnn],dis3[maxnn],dis4[maxnn];
ll n,m,s,t,u,v;
struct node
{
	int st,en;
	ll l;
	ll d;
}ed[maxnn];
int cnt;

void add(int a,int b,ll c)
{
	en[++tot]=b;
	nex[tot]=las[a];
	las[a]=tot;
	le[tot]=c;
}

void zadd(int a,int b,ll c)
{
	zen[++ztot]=b;
	znex[ztot]=zlas[a];
	zlas[a]=ztot;
	zle[ztot]=c;
}
typedef pair<ll ,int > P;
priority_queue<P ,vector<P>,greater<P> > Q;
void dij(ll *dis,int v)
{
	for(int i=1;i<=n;i++)
	{
		dis[i]=inf;
	}
	dis[v]=0;
	Q.push(make_pair(dis[v],v));
	while(Q.size())
	{
		P s=Q.top();
		Q.pop();
		if(s.first!=dis[s.second]) continue;
		for(int i=las[s.second];i;i=nex[i])
		{
			int u=en[i];
			if(dis[u]>dis[s.second]+le[i])
			{
				dis[u]=dis[s.second]+le[i];
				Q.push(make_pair(dis[u],u));
			}
		}
	}
}
ll dis[maxnn];
ll f[maxnn][3];
ll ans=111111111000000;
void ddij(int v)
{
	for(int i=1;i<=n;i++)
	{
		f[i][0]=f[i][1]=inf;
	}
	for(int i=1;i<=n;i++)
	{
		dis[i]=inf;
	}
	dis[v]=0;
	f[v][0]=dis3[v];
	f[v][1]=dis4[v];
	Q.push(make_pair(dis[v],v));
	while(Q.size())
	{
		P s=Q.top();
		Q.pop();
		if(s.first!=dis[s.second]) continue;
		for(int i=zlas[s.second];i;i=znex[i])
		{
			int u=zen[i];
			if(dis[u]==dis[s.second]+zle[i])
			{
				dis[u]=dis[s.second]+zle[i];
				f[u][0]=min(f[u][0],min(f[s.second][0],dis3[u]));
				f[u][1]=min(f[u][1],min(f[s.second][1],dis4[u]));
			}
			if(dis[u]>dis[s.second]+zle[i])
			{
				dis[u]=dis[s.second]+zle[i];
				f[u][0]=min(f[s.second][0],dis3[u]);
				f[u][1]=min(f[s.second][1],dis4[u]);
				Q.push(make_pair(dis[u],u));
			}
		}
	}
}
int main()
{
	ll x,y,z;
	scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&s,&t,&u,&v);
	for(int i=1;i<=m;i++)
	{
		scanf("%lld%lld%lld",&x,&y,&z);
		add(x,y,z);
		add(y,x,z);
		ed[++cnt].st=x;
		ed[cnt].en=y;
		ed[cnt].l=z;
	}
	dij(dis1,s);
	dij(dis2,t);
	dij(dis3,u);
	dij(dis4,v);
	for(int i=1;i<=cnt;i++)
	{
		if(dis1[ed[i].st]+dis2[ed[i].en]+ed[i].l==dis1[t])
		{
			zadd(ed[i].st,ed[i].en,ed[i].l);
		}
		if(dis1[ed[i].en]+dis2[ed[i].st]+ed[i].l==dis1[t])
		{
			zadd(ed[i].en,ed[i].st,ed[i].l);
		}
	}
	ddij(s);
	for(int i=1;i<=n;i++)
	{
		ans=min(ans,f[i][1]+dis3[i]);
		ans=min(ans,f[i][0]+dis4[i]);
	}
	ans=min(ans,dis3[v]);
	cout<<ans;
	
}

posted @ 2019-11-07 10:52  ALEZ  阅读(322)  评论(0编辑  收藏  举报