orz一开始想不画图做这个题(然后脑袋就炸了,思维能力有待提高)
我的做法是动态规划+贪心+构造
首先把题目给的树变成一个可行的情况,同时weight最小
这个可以通过动态规划解决 dp[x]表示以x为结点的子树,它的最小weight是多少
接着我们就只需要考虑每条边增加多少就可以了,这里可以用贪心的做法
ddfs(int x, int fa, int v) 这里v是表示给x结点最大多少增量,然后慢慢加就可以,返回没用掉的增量
其实这个做法有点奇怪,应该有更简便的做法(我觉得可以直接贪心做)
#include <iostream> #include <cstdio> #include <vector> using namespace std; const int maxn = 4*111111; const long long Give = 2e18; struct Edge { int from, to; long long w, v; }; vector<Edge> edges; vector<int> G[maxn]; long long dp[maxn], delta[maxn], dd[maxn], Fail; void addedge(int from, int to, int w, int v) { edges.push_back((Edge){from, to, w, v}); edges.push_back((Edge){to, from, w, v}); int m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } void dfs(int x, int fa) { dp[x] = 0; for(int i = 0; i < G[x].size(); i++) { Edge &e = edges[G[x][i]]; if(e.to == fa) continue; dfs(e.to, x); if(e.v - dp[e.to] < 0) Fail = 1; delta[G[x][i]] = min(e.w-1, e.v - dp[e.to]); dp[x] += (e.w - delta[G[x][i]] + dp[e.to]); } } long long ddfs(int x, int fa, long long v) { long long ans = 0; //cout<<x<<endl<<endl; for(int i = 0; i < G[x].size(); i++) { Edge &e = edges[G[x][i]]; if(e.to == fa) continue; long long t = min(v, delta[G[x][i]]); ans += t; v -= t; dd[G[x][i]] = delta[G[x][i]] - t; dd[G[x][i]^1] = dd[G[x][i]]; long long dt = ddfs(e.to, x, min(v, e.v-dd[G[x][i]]-dp[e.to])); ans += dt; v -= dt; } return ans; } int n, x, y, w, v; int main() { //freopen("a.txt", "r", stdin); cin.sync_with_stdio(false); cin>>n; for(int i = 1; i < n; i++) { cin>>x>>y>>w>>v; addedge(x, y, w, v); } dfs(1, 1); //for(int i = 1; i <= n; i++) cout<<i<<" "<<dp[i]<<endl; if(Fail) cout<<"-1"; else { ddfs(1, 1, Give); cout<<n<<endl; for(int i = 0; i < 2*(n-1); i += 2) { Edge &e = edges[i]; cout<<e.from<<" "<<e.to<<" "<<e.w - dd[i]<<" "<<e.v - dd[i]<<endl; } } }
时间: 2024-10-14 10:29:22