Loading

P2886 [USACO07NOV] Cow Relays G - 贪心

获得更好的阅读体验

本文参考高逸涵的《部分贪心思想在信息学竞赛中的应用》。

一种 \(\mathcal{O}(T^2)\) 的做法

首先感性理解一下:当 \(N\) 很大的时候,最优策略一定是在某个边权很小的边上绕圈。


性质 1:只有可能在路径上一条最短的边上连续走多次。

证明:假如在其他边上连续走了多次,那我们可以将路径上来回走的一对边 \((u\to v,v\to u)\) 删去,换成在最短的边上来回走,这样一定不劣。


性质 2:只有路径上的一条最短边可能被在同一方向经过三次及以上,这里“经过”不要求连续。

证明:假如另外一条边被在同一方向经过三次及以上,那么路径上一定有包含这条边的两个环。若这两个环中有至少一个长度为偶数,那么可以删去这个环并在最短边上来回走;否则,两个环的长度都是奇数,把两个环都删去,换成在最短边上来回走即可。


结论:最优方案下,只会有至多一条边被经过 \(>2\) 次。

\(f_{u,d}\) 表示从 \(S\)\(u\),经过的边数为 \(d\) 的最短路。由于每条边都被经过 \(\le 2\) 次,只需算出 \(d\le 2T\)\(f\) 即可。于是可以 \(\mathcal{O}(T^2)\) 预处理。同理,预处理 \(g_{u,d}\) 表示从 \(E\) 的。

枚举每条边作为那条被多次经过的边,并 \(\mathcal{O}(T)\) 算出最小值即可。具体计算方式可见代码中的 Calc 函数。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
#define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
typedef long long ll;
const int N=1005,M=105,Inf=0x3f3f3f3f;
int n;
int Get(int u){
	static int num[N]{};
	if(!num[u]) return num[u]=++n;
	return num[u];
}
int t,m,S,T,f[M][M<<1],g[M][M<<1];
struct Edge{int u,v,w;}edge[M];
int Calc(int u,int len){
	int res=Inf;
	For(c,0,1){
		int mn=Inf,k=(t+c)%2-2;
		for(int j=m*2+c;j>=0;j-=2){
			while(k<m*2&&t-j-k>1){
				k+=2,mn+=2*len;
				mn=min(mn,g[u][k]);
			}
			if(mn>=Inf||f[u][j]>=Inf) continue;
			res=min(res,mn+f[u][j]+(t-j-k)*len);
		}
	}
	return res;
}
int main(){
	cin>>t>>m>>S>>T;
	S=Get(S),T=Get(T);
	For(i,1,m){
		cin>>edge[i].w>>edge[i].u>>edge[i].v;
		edge[i].u=Get(edge[i].u),edge[i].v=Get(edge[i].v);
	}
	memset(f,0x3f,sizeof f),memset(g,0x3f,sizeof g);
	f[S][0]=0,g[T][0]=0;
	For(i,1,m*2){
		For(j,1,m){
			f[edge[j].u][i]=min(f[edge[j].u][i],f[edge[j].v][i-1]+edge[j].w);
			f[edge[j].v][i]=min(f[edge[j].v][i],f[edge[j].u][i-1]+edge[j].w);
			g[edge[j].u][i]=min(g[edge[j].u][i],g[edge[j].v][i-1]+edge[j].w);
			g[edge[j].v][i]=min(g[edge[j].v][i],g[edge[j].u][i-1]+edge[j].w);
		}
	}
	int ans=Inf;
	For(i,1,m){
		ans=min({ans,Calc(edge[i].u,edge[i].w),Calc(edge[i].v,edge[i].w)});
	}
	cout<<ans;
	return 0;
}
posted @ 2021-11-19 10:07  Alan_Zhao_2007  阅读(162)  评论(1编辑  收藏  举报