P3354 [IOI2005]Riv 河流

写的过程十分煎熬,实在是不会写,还要继续熟悉啥是背包。。。。
动态规划最难的不是转移方程,而是设计dp的含义啊

洛谷题目传送门

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn = 200 + 11;
typedef long long ll;
ll f[110][110][110], g[110][110][110];
int k, n, m;
ll sum[110], dis[maxn];

struct Node {
	int p;
	int len;
	Node(int a, int b) :p(a), len(b) {}
};
vector<Node>G[maxn];
void add(int be, int en, int len) {
	G[be].push_back(Node(en, len));
}
int s[maxn];
int cnt = 0;

int dfs(int x, int fa, ll d) {
	s[cnt++] = x;
	dis[x] = d;

	for (int i = 0; i < G[x].size(); i++) {
		int p = G[x][i].p;
		ll ln = G[x][i].len;
		if (p == fa) continue;

		dfs(p, x, d + ln);

		for (int b = 0; b < cnt; b++) {
			int ff = s[b];
			for (int j = k; j >= 0; j--) {
				f[x][ff][j] += f[p][ff][0];
				g[x][ff][j] += f[p][x][0];
				for (int a = 0; a <= j; a++) {//01背包
					f[x][ff][j] = min(f[x][ff][j], f[x][ff][j - a] + f[p][ff][a]);
					g[x][ff][j] = min(g[x][ff][j], g[x][ff][j - a] + f[p][x][a]);
				}
			}
		}
	}

	//补齐x--->ff的流量

	for (int i = 0; i < cnt; i++) {
		int ff = s[i];
		for (int j = 0; j <= k; j++) {
			if (j == 0) {
				f[x][ff][j] += sum[x] * (dis[x] - dis[ff]);
			}
			else {
				//判断是否让x成为工厂
				f[x][ff][j] = min(f[x][ff][j] + sum[x] * (dis[x] - dis[ff]), g[x][ff][j - 1]);
			}
		}
	}

	cnt--;
	return 0;
}


int main() {
	scanf("%d %d", &n, &k);

	for (int i = 1; i <= n; i++) {
		int be = i, en, len;
		scanf("%lld %d %d", &sum[i], &en, &len);
		add(be, en, len);
		add(en, be, len);
	}
	cnt = 0;
	dfs(0, -1, 0);
	printf("%lld
", f[0][0][k]);
	return 0;
}

  

原文地址:https://www.cnblogs.com/lesning/p/14088850.html