BZOJ4711 小奇挖矿

挺神的DP题

考虑f[i][j]表示i的子树内所有点都确定了往哪送,并且i送到j号点,并且j号点现在还未建立仓库(如果有不等于j的点需要有仓库的话,那么已经建好了)的最小代价

考虑转移,首先f[i][j]要加上从i到j的代价,然后考虑i的每一个儿子i',如果i'也运到j,那么这个子树的代价就是f[i'][j]

如果i'运到一个不等于j的点j',那么j'一定在以i'为根的子树里,因为否则的话令j=j'或j'=j会更优,那么这时我们令这个子树的代价为f[i'][j']+k,这样每个被建立的仓库只会被算一次

答案为min(f[1][i])+k

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXN 210
#define MAXM 1010
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
struct vec{
	int to;
	int fro;
};
vec mp[MAXN*2];
int tai[MAXN],cnt;
int v[MAXN];
int n,m;
int d[MAXN][MAXN];
int tim;
int g[MAXN][MAXN];
void dfs(int x,int f,int *d){
	int i,y;
	for(i=tai[x];i;i=mp[i].fro){
		y=mp[i].to;
		if(y!=f){
			d[y]=d[x]+1;
			dfs(y,x,d);
		}
	}
}
inline void be(int x,int y){
	mp[++cnt].to=y;
	mp[cnt].fro=tai[x];
	tai[x]=cnt;
}
inline void bde(int x,int y){
	be(x,y);
	be(y,x);
}
void dp(int x,int f){
	int I,y,i,j;
	for(i=tai[x];i;i=mp[i].fro){
		y=mp[i].to;
		if(y!=f){
			dp(y,x);
		}
	}
	for(i=1;i<=n;i++){
		g[x][i]+=v[d[x][i]];
		for(I=tai[x];I;I=mp[I].fro){
			y=mp[I].to;
			if(y!=f){
				int t=g[y][i];
				for(j=1;j<=n;j++){
					t=min(t,g[y][j]+m);
				}
				g[x][i]+=t;
			}
		}
	}
}
int main(){
	int i,x,y;
	scanf("%d%d",&n,&m);
	for(i=1;i



你可能感兴趣的:(BZOJ,DP,递推)