【OpenJudge - noi - 7624】山区建小学(dp)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/87987128

题干:

总时间限制: 

1000ms

内存限制: 

65536kB

描述

政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往。已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0 < i < m。为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设 0 < n < = m < 500 )。请根据给定的m、n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值。

输入

第1行为m和n,其间用空格间隔
第2行为(m-1) 个整数,依次表示从一端到另一端的相邻村庄的距离,整数之间以空格间隔。

例如
10 3
2 4 6 5 2 4 3 1 3
表示在10个村庄建3所学校。第1个村庄与第2个村庄距离为2,第2个村庄与第3个村庄距离为4,第3个村庄与第4个村庄距离为6,...,第9个村庄到第10个村庄的距离为3。

输出

各村庄到最近学校的距离之和的最小值。

样例输入

10 2
3 1 3 1 1 1 1 1 3

样例输出

18

解题报告:

   dp[i][j]代表前i个村庄建立了j所小学的最小距离。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e5 + 5;
const int INF = 0x3f3f3f3f;
//从m个村中选择n个村建小学(设 0 < n < = m < 500 )
int dis[555][555];
int f[555][555];
int dp[555][555];//dp[i][j] 代表前i个村庄创建n个j个学校的最小距离。
int go(int i,int j) {
	int mid = (i+j)>>1;
	int res = 0;
	for(; i<=j; i++) res += dis[i][mid];
	return res;
}
int n,m;
int main() {
	cin>>m>>n;
	for(int i = 1; i<=m; i++) dis[i][i] = 0;
	for(int x,i = 2; i<=m; i++) {
		scanf("%d",&x);
		dis[i-1][i] = dis[i][i-1] = x;//其实这一句可以合并到下面,因为你dis[i][i]=0了。。
		for(int j = 1; j<i; j++) {
			dis[j][i] = dis[j][i-1] + x;
			dis[i][j] = dis[j][i];
		}
	}
	for(int i = 1; i<=m; i++) {
		for(int j = 1; j<=m; j++) {
			f[i][j] = go(i,j);
		}
	}
	memset(dp,INF,sizeof dp);
	for(int i = 1; i<=m; i++) dp[i][1] = f[1][i];
	for(int i = 2; i<=m; i++) {
		for(int j = 2; j<=n; j++) {
			if(j > i) continue;
			for(int k = 1; k<i; k++) {
				dp[i][j] = min(dp[i][j],dp[k][j-1] + f[k+1][i]);
			}

		}
	}
	printf("%d\n",dp[m][n]);
	return 0 ;
}
//19:11 - 19:28

简化一点的:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e5 + 5;
const int INF = 0x3f3f3f3f;
//从m个村中选择n个村建小学(设 0 < n < = m < 500 )
int sum[555];
int f[555][555];
int dp[555][555];//dp[i][j] 代表前i个村庄创建n个j个学校的最小距离。
int go(int i,int j) {
	int mid = (i+j)>>1;
	int res = 0;
	for(; i<=j; i++) res += abs(sum[mid]-sum[i]);
	return res;
}
int n,m;
int main() {
	cin>>m>>n;
	for(int x,i = 2; i<=m; i++) {
		scanf("%d",&x);
		sum[i] = sum[i-1] + x;//边的前缀和 
	}
	for(int i = 1; i<=m; i++) {
		for(int j = 1; j<=m; j++) {
			f[i][j] = go(i,j);
		}
	}
	memset(dp,INF,sizeof dp);
	for(int i = 1; i<=m; i++) dp[i][1] = f[1][i];
	for(int i = 2; i<=m; i++) {
		for(int j = 2; j<=n; j++) {
			if(j > i) continue;
			for(int k = j-1; k<i; k++) {
				dp[i][j] = min(dp[i][j],dp[k][j-1] + f[k+1][i]);
			}
		}
	}
	printf("%d\n",dp[m][n]);
	return 0 ;
}
//19:11 - 19:28

或者分治:(但是这个耗时400ms??上面那个dp只有100多ms)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define rep(i,a,b) for(int i=a;i<b;i++)
using namespace std;
const int MAX = 2e5 + 5;

const ll INF=1e15;
int a[MAX];
ll dp[MAX],ndp[MAX],s[MAX];
ll cal(int l,int r) {
	return s[r]+s[l-1]-s[(l+r-1)/2]-s[(l+r)/2];
}
void solve(int l,int r,int p,int q) {
	if(l>r)return;
	int m=(l+r)>>1,x=p;
	ndp[m]=INF;
	for(int i = p; i<=q; i++) {
		ll w=dp[i]+cal(i+1,m);
		if(ndp[m]>w) {
			ndp[m]=w;
			x=i;
		}
	}
	if(l<r) {
		solve(l,m-1,p,x);
		solve(m+1,r,x,q);
	}
}
int main() {
	int T,ca=0,k,i,j,m=0,K,n;
	scanf("%d%d",&n,&K);
	K = min(K,n);
	a[1]=0;
	for(int i = 2; i<=n; i++) {
		int q;
		scanf("%d",&q);
		a[i] = a[i-1] + q;
	}
	sort(a+1,a+n+1);
	for(int i = 1; i<=n; i++)s[i]=s[i-1]+a[i];
	for(int i = 1; i<=n; i++) dp[i]=INF;
	for(int i = 1; i<=K; i++) {
		solve(1,n,0,n);
		swap(dp,ndp);
	}
	printf("%lld\n",dp[n]);
	return 0 ;
}

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/87987128