洛谷P6158 封锁,平面图最小乘积最短路

好久没有写Blog,这个寒假打比赛打得挺顺利的。

正题

      Portal

      其实是最后不够时间了,这道题两个part我都做过。

      如果没有AB两个权值那么就是平面图最小割的问题,转化为最短路就可以解决了,具体做法就是把左下角的空白看成起点,右上角的空白看成终点,如果假设要使一条边不能走相当于穿过这条边,会发现最后的决策其实是新起点到新终点的一条路径。

      假若有两个值呢?发现乘积最小值的决策点大致分布在一个下凸包上,每一个决策点代表一种AB,如果不怎么会,就去做做最小乘积生成树或者画框,就可以了。

#include<bits/stdc++.h>
using namespace std;

const int N=410;
int n;
int st,ed;
struct edge{
	int y,next,a,b;
}s[N*N<<1];
struct node{
	int x;
	long long d;
	bool operator<(const node q)const{
		return d>q.d;
	}
};
priority_queue<node> f;
long long dis[N*N];
int A[N*N],B[N*N];
int first[N*N],len=0;
long long ans=1e18;

void ins(int x,int y,int a,int b){
	s[++len]=(edge){y,first[x],a,b};first[x]=len;
}

pair<int,int> Dijkstra(int ta,int tb){
	ta=-ta,tb=-tb;
	while(!f.empty()) f.pop();
	memset(dis,63,sizeof(dis));
	f.push((node){st,0});dis[st]=0;A[st]=B[st]=0;
	while(!f.empty()){
		node X=f.top();f.pop();
		if(X.d!=dis[X.x]) continue;
		if(X.x==ed) break;
		for(int i=first[X.x];i!=0;i=s[i].next) if(dis[s[i].y]>X.d+1ll*ta*s[i].a+1ll*tb*s[i].b){
			dis[s[i].y]=X.d+1ll*ta*s[i].a+1ll*tb*s[i].b;
			A[s[i].y]=A[X.x]+s[i].a,B[s[i].y]=B[X.x]+s[i].b;
			f.push((node){s[i].y,dis[s[i].y]});
		}
	}
	ans=min(ans,1ll*A[ed]*B[ed]);
	return make_pair(A[ed],B[ed]);
}

void solve(pair<int,int> L,pair<int,int> R){
	pair<int,int> now=Dijkstra(R.second-L.second,L.first-R.first);
	if(1ll*(now.first-L.first)*(R.second-L.second)-1ll*(now.second-L.second)*(R.first-L.first)>0) solve(L,now),solve(now,R);
	else return ;
}

int main(){
	scanf("%d",&n);
	int x,y;ed=(n-1)*(n-1)+1;
	for(int i=1;i<n;i++){
		scanf("%d %d",&x,&y);
		ins(st,(i-1)*(n-1)+1,x,y);
		for(int j=1;j<n-1;j++)
			scanf("%d %d",&x,&y),ins((i-1)*(n-1)+j,(i-1)*(n-1)+j+1,x,y);
		scanf("%d %d",&x,&y);
		ins(i*(n-1),ed,x,y);
	}
	for(int i=1;i<n;i++) scanf("%d %d",&x,&y),ins(i,ed,x,y);
	for(int i=2;i<=n-1;i++)
		for(int j=1;j<n;j++)
			scanf("%d %d",&x,&y),ins((i-1)*(n-1)+j,(i-2)*(n-1)+j,x,y);
	for(int i=1;i<n;i++) scanf("%d %d",&x,&y),ins(st,(n-2)*(n-1)+i,x,y);
	solve(Dijkstra(-1,0),Dijkstra(0,-1));
	printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/104625062