题目链接:点击打开链接
思路:
选一些边, 使得任意两点都可以相互到达且花费最小, 这显然是最小生成树, 将边挑选出来之后, 如果贪心选取的话, 有可能导致无解, 所以我们考虑用动态规划。
根据数据量, 用d[i][j]表示前i个边, 第一种颜料用了j单位长度下的最小花费, 因为没条边都选, 那么用总和减去j就是第二种颜料的花费。 用path[i][j]表示改状态下从哪一个状态转移过来的, 注意到第一维不需要记录, 只记录第二维就行了。
细节参见代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <ctime>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
typedef long double ld;
const double eps = 1e-6;
const double PI = acos(-1);
const int mod = 1000000000 + 7;
const int INF = 0x3f3f3f3f;
// & 0x7FFFFFFF
const int seed = 131;
const ll INF64 = ll(1e18);
const int maxn = 10000 + 10;
int T,n,m,p[1010],d[1010][maxn],sum[1010];
short path[1010][maxn];
struct node {
int a, b, c, id;
node(int a=0, int b=0, int c=0, int id=0):a(a), b(b), c(c), id(id) {}
bool operator < (const node& rhs) const {
return c < rhs.c;
}
}e[maxn];
int _find(int x) { return p[x] == x ? x : p[x] = _find(p[x]); }
struct Edge {
int a, b, c, id;
Edge(int a=0, int b=0, int c=0, int id=0):a(a), b(b), c(c), id(id) {}
bool operator < (const Edge& rhs) const {
return id > rhs.id;
}
} edge[maxn];
int main() {
while(~scanf("%d%d", &n, &m)) {
for(int i = 1; i <= m; i++) {
scanf("%d%d%d", &e[i].a, &e[i].b, &e[i].c);
e[i].id = i;
}
sort(e+1, e+m+1);
int cnt = 0;
for(int i = 0; i <= n; i++) p[i] = i;
for(int i = 1; i <= m; i++) {
int x = _find(e[i].a);
int y = _find(e[i].b);
if(x != y) {
p[x] = y;
edge[++cnt] = Edge(e[i].a,e[i].b,e[i].c,e[i].id);
}
}
int p5, p6, q5, q6;
scanf("%d%d%d%d", &p5, &q5, &p6, &q6);
if(cnt != n-1) {
printf("Impossible\n");
continue;
}
sort(edge+1, edge+cnt+1);
for(int i = 1; i <= cnt; i++) sum[i] = sum[i-1] + edge[i].c;
memset(d, 0x3f, sizeof(d));
d[0][0] = 0;
for(int i = 1; i <= cnt; i++) {
for(int j = 0; j <= q5; j++) {
if(sum[i]-j >= edge[i].c && sum[i]-j <= q6 && d[i-1][j] != INF) {
if(d[i][j] > d[i-1][j] + edge[i].c*p6) {
d[i][j] = d[i-1][j] + edge[i].c*p6;
path[i][j] = j;
}
}
if(j >= edge[i].c && d[i-1][j-edge[i].c] != INF) {
if(d[i][j] > d[i-1][j-edge[i].c] + edge[i].c*p5) {
d[i][j] = d[i-1][j-edge[i].c] + edge[i].c*p5;
path[i][j] = j-edge[i].c;
}
}
}
}
int ans = INF, pos = 0;
for(int i = 0; i <= q5; i++) {
if(ans > d[cnt][i]) {
ans = d[cnt][i];
pos = i;
}
}
if(ans == INF) {
printf("Impossible\n");
continue;
}
int res = cnt;
printf("%d\n", ans);
while(res > 0) {
printf("%d ", edge[res].id);
if(pos == path[res][pos]) printf("6\n");
else printf("5\n");
pos = path[res][pos];
res--;
}
}
return 0;
}