zoukankan      html  css  js  c++  java
  • 【USACO 2017 December Gold】A Pie for a Pie 题解

    思路

    首先注意到题目中的几个性质:

    1. 不会送出同一个 (pi) ,题目不允许,而且也不可能是最优方案。
    2. 如果送出某个 (pi) (除了第一个),那么刚刚收到的 (pi) 肯定是固定的某些 (pi)

    那么基于此,设 (B_i) 为Bessie做的第 (i)(pi) 的答案、 (E_i) 为Elsie做的第 (i)(pi) 的答案,我们可以设出转移方程:

    (B_i=egin{cases}1& ext{如果Elsie的评价为0}\min{{E_j}}& ext{如果Elsie对当前}pi ext{的评价}leq ext{对Elsie做的第}j ext{个}pi ext{的评价}end{cases})

    (E_i=egin{cases}1& ext{如果Bessie的评价为0}\min{{B_j}}& ext{如果Bessie对当前}pi ext{的评价}leq ext{对Bessie做的第}j ext{个}pi ext{的评价}end{cases})

    明显的(也就想了我半个小时),这是一个最短路的模型,所以我们把Bessie做的 (pi) 设成 (1)~(n) 号点,把Elsie做的 (pi) 设成 (n+1)~(n+n) 号点,然后建图,然后跑最短路即可。

    实现

    建图明显是 (n^2) 的(其实本来就是 (n^2) 的,但是数据……),考虑优化至(nlog{n}),有两种方法:

    1. 把Bessie做的 (pi) 按Bessie的评价排序,把Elsie做的 (pi) 按Elsie的评价排序。

      对于一个Bessie做的 (pi) ,用二分找到最小可以让Elsie送出哪个 (pi) ,然后一个一个建边直到不能建边为止。对于Elsie做的 (pi) 同理。

    2. 把所有的 (pi) copy一份放在另一个数组里,然后Bessie的 (pi) 分别按Bessie的评价和Elsie的评价排序。对于Elsie做的 (pi) 同理。

      对于一个Bessie做的 (pi) ,用另一个只增不减的指针找到最小可以让Elsie送出哪个 (pi) ,然后再用一个循环一个一个建边直到不能建边为止。对于Elsie做的 (pi) 同理。

    注意:连边时要反着连,然后再构造一个源点连到每一个“出口”的点(即 (B_i)(E_i) 为1的点)。并不需要特殊处理答案,对于一个点只要有一个0就可以认为是“出口”(数据过水)。

    然后建图就完成了,跑最短路即可。

    Code

    Warning:建边部分可能引起不适,请谨慎观看

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,m,w[200010],a[200010][2],cb[2][100010],ce[2][100010],last,h[200010],b[1500010][2],d[200010];
    bool bz[200010];
    void read(int &x){
    	char c=getchar();
    	for(;c<33;c=getchar());
    	for(x=0;(47<c)&&(c<58);x=x*10+c-48,c=getchar());
    }
    bool comp1(int x,int y){
    	return(a[x][0]<a[y][0]);
    }
    bool comp2(int x,int y){
    	return(a[x][1]<a[y][1]);
    }
    void add(int x,int y){
    	b[++last][0]=h[x];
    	b[last][1]=y;
    	h[x]=last;
    }
    void spfa(){
    	int dh=0,dt=1;
    	memset(w,127,sizeof(w));
    	w[0]=0;
    	while(dh<dt){
    		for(int i=h[d[++dh]];i;i=b[i][0]){
    			if(w[b[i][1]]>w[d[dh]]+1){
    				w[b[i][1]]=w[d[dh]]+1;
    				if(!bz[b[i][1]]){
    					d[++dt]=b[i][1];
    					bz[b[i][1]]=1;
    				}
    			}
    		}
    		bz[d[dh]]=0;
    	}
    }
    int main(){
    	freopen("piepie.in","r",stdin);
    	freopen("piepie.out","w",stdout);
    	read(n);read(m);
    	for(int i=1;i<=n;i++){
    		read(a[i][0]);read(a[i][1]);
    		cb[0][i]=cb[1][i]=i;
    	}
    	for(int i=1;i<=n;i++){
    		read(a[i+n][0]);read(a[i+n][1]);
    		ce[0][i]=ce[1][i]=i+n;
    	}
    	sort(cb[0]+1,cb[0]+n+1,comp1);
    	sort(cb[1]+1,cb[1]+n+1,comp2);
    	sort(ce[0]+1,ce[0]+n+1,comp1);
    	sort(ce[1]+1,ce[1]+n+1,comp2);
    	for(int i=1,j=1;i<=n;i++){
    		for(;a[cb[1][i]][1]>a[ce[1][j]][1]&&j<=n;j++);
    		if(a[cb[1][i]][1]==0){
    			add(0,cb[1][i]);
    			continue;
    		}
    		for(int k=j;a[cb[1][i]][1]+m>=a[ce[1][k]][1]&&k<=n;add(ce[1][k],cb[1][i]),k++);
    	}
    	for(int i=1,j=1;i<=n;i++){
    		for(;a[ce[0][i]][0]>a[cb[0][j]][0]&&j<=n;j++);
    		if(a[ce[0][i]][0]==0){
    			add(0,ce[0][i]);
    			continue;
    		}
    		for(int k=j;a[ce[0][i]][0]+m>=a[cb[0][k]][0]&&k<=n;add(cb[0][k],ce[0][i]),k++);
    	}
    	spfa();
    	for(int i=1;i<=n;i++){
    		printf("%d
    ",w[i]==0x7f7f7f7f?-1:w[i]);
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return(0);
    }
    
  • 相关阅读:
    关于float和double类型能表示的数据范围和精度分析
    P2737 [USACO4.1]麦香牛块Beef McNuggets 数学题 + 放缩思想
    csu 1554: SG Value 思维题
    csu 1551: Longest Increasing Subsequence Again BIT + 思维
    Rasheda And The Zeriba Gym
    cpc,a wonderful concert
    hdu_3308 区间合并
    poj_3667线段树区间合并
    poj_2777线段树+位运算
    poj_3468,线段树成段更新
  • 原文地址:https://www.cnblogs.com/groundwater/p/13027194.html
Copyright © 2011-2022 走看看