zoukankan      html  css  js  c++  java
  • P4767 IOI2000 邮局

    (n) 个村庄,给出了他们的横坐标。现在要在这些村庄中的一些村庄安放 (p) 个邮局,要求算每个村庄和最近的邮局之间所有距离的最小可能的总和。

    (50\%:sim70\%)

    悄咪咪告诉你,开氧可以跑(90pts!!!!!!!!!!) 这还打啥正解

    (f[i][j])表示前(i)个村庄放(j)个邮局最小距离和

    (w[i][j])表示村庄区间([i,j])内放(1)个邮局的距离和

    (w)可以预处理出来,放置一个邮局,邮局位置总是在中位数处

    (w[l][r]=w[l][r-1]+X[r]-X[frac{l+r}2]) (V^2)递推

    (f[i][j]=min{f[k][j-1]+w[k+1][j])}~~kin[0,i))

    复杂度(O(PV^2))

    const int N = 3005;
    int V,P,x[N],w[N][N],f[N][305];
    inline int min(int a,int b){return a < b ? a : b;}
    void init(){
    	for(re int i = 1;i <= V;++i) x[i] = read();
    	for(re int i = 1;i <= V;++i)
    		for(re int j = i+1;j <= V;++j)
    			w[i][j] = w[i][j-1] + x[j] - x[i+j>>1];
    }
    int main(){
    	V = read(); P = read();
    	init();
    	memset(f,0x3f,sizeof(f));
    	f[0][0] = 0;
    	for(re int j = 1;j <= P;++j)
    		for(re int i = 1;i <= V;++i)
    			for(re int k = 0;k < i;++k)
    				f[i][j] = min(f[k][j-1] + w[k+1][i],f[i][j]);
    	printf("%d",f[V][P]);
    }
    

    (100\%:)

    (w)其实是满足四边形不等式的

    由递推式可得(w[l][r+1]-w[l][r]=X[r+1]-X[frac{l+r+1}2]~~①)

    [w[l+1][r+1]-w[l+1][r]=X[r+1]-X[frac{l+r+2}2]~~②\ ①-②\ =X[frac{l+r+2}2]-X[frac{l+r+1}2]\ ]

    (X)递增,则(large X[frac{l+r+2}2]-X[frac{l+r+1}2]ge0)

    [w[l][r+1]-w[l][r]-(w[l+1][r+1]-w[l+1][r])ge0\ w[l][r+1]-w[l][r]-w[l+1][r+1]+w[l+1][r]ge0\ w[l][r+1]+w[l+1][r]ge w[l][r]+w[l+1][r+1] ]

    显然(w)满足四边形不等式,且对于(ale ble cle d)(w[a][d]ge w[b][c])(dp)满足四边形不等式

    所以对于(f[i][j])决策,(f[i][j-1]le f[i][j]le f[i+1][j])

    (s[i][j])(i)之前建(j)个邮局的最优决策

    所以转移(f[i][j])时,从([s[i][j-1],s[i+1][j]])中找最优决策

    因为要用到(f[i+1][j]),所以倒叙枚举(i)

    (O(PV))

    int V,P,x[N],w[N][N],f[N][305],s[N][305];
    void init(){
    	for(int i = 1;i <= V;++i) x[i] = read();
    	for(int i = 1;i <= V;++i)
    		for(int j = i+1;j <= V;++j)
    			w[i][j] = w[i][j-1] + x[j] - x[i+j>>1];
    }
    int main(){
    	V = read(); P = read();
    	init();
    	memset(f,0x3f,sizeof(f));
    	f[0][0] = 0;
    	for(int j = 1;j <= P;++j){
    		s[V + 1][j] = V;
    		for(int i = V;i >= 1;--i){ 
    			int minn = 0x3f3f3f3f,minid;
    			for(int k = s[i][j-1];k <= s[i+1][j];++k){
    				if(f[k][j-1] + w[k+1][i] < minn){
    					minn = f[k][j-1] + w[k+1][i];
    					minid = k;
    				}
    			}
    			f[i][j] = minn; s[i][j] = minid;	
    		} 
    	}
    	printf("%d",f[V][P]);
    }
    
  • 相关阅读:
    史上最全最新java面试题合集二(附答案)
    史上最全最新Java面试题合集一(附答案)
    修改vsftpd的默认根目录/var/ftp/pub到其他目录
    重置密码解决MySQL for Linux错误:ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
    虚拟机下的Linux连接校园网上网问题
    CentOS7 安装Chrome
    CentOS7 卸载Firefox
    100个写作高级词
    【二叉搜索树】的详细实现(C++)
    【红黑树】的详细实现(C++)
  • 原文地址:https://www.cnblogs.com/shikeyu/p/13822303.html
Copyright © 2011-2022 走看看