最长路:
设置一个虚拟起点和虚拟终点,每个点与起点间一条负边,值为这个点书的价值的相反数(代表买书花钱),每个点与终点连一条正边,值为这个点的书的价格(代表卖书赚钱)。
然后按照图中给的边建无向边,权值为负(代表路费)。跑最长路,spfa改一下松弛条件就行
#include<cstdio> #include<vector> #include<cstring> #include<queue> using namespace std; const int maxn = 100000+10; const int inf = 1e9; int n; int cost[100000+10]; struct node { int to; int w; node(int a,int b):to(a),w(b){} }; vector<node>G[maxn]; int dist[maxn],vis[maxn]; void spfa() { queue<int>q; for(int i=0;i<=n+1;i++) dist[i] = -inf; memset(vis,0,sizeof(vis)); q.push(0); vis[0] = 1; dist[0] = 0; while(!q.empty()) { int u = q.front(); q.pop(); int len = G[u].size(); for(int i=0;i<len;i++) { int v = G[u][i].to; int w = G[u][i].w; if(dist[v]<dist[u]+w) { dist[v] = dist[u] + w; if(!vis[v]){vis[v] = 1; q.push(v); } } } vis[u] = 0; } printf("%d ",dist[n+1]); } int main() { int cases,u,v,w; scanf("%d",&cases); while(cases--) { scanf("%d",&n); for(int i=0;i<n+5;i++) G[i].clear(); for(int i=1;i<=n;i++) scanf("%d",&cost[i]); for(int i=1;i<=n;i++) { G[0].push_back(node(i,-cost[i])); G[i].push_back(node(n+1,cost[i])); } for(int i=1;i<n;i++) { scanf("%d%d%d",&u,&v,&w); G[u].push_back(node(v,-w)); G[v].push_back(node(u,-w)); } spfa(); } return 0; }
树形DP:
设1为根节点,假设一开始一个人身上的钱为0。
我们设dp[i][0]表示从根节点走到i及其子树并中任一点买入一本书后这个人身上钱的最大值(显然是负的)。
dp[i][1]表示从根节点走到i及其子树并中任一点卖出一本书后这个人身上钱的最大值(可正可负)。
那么我们对这棵树进行一次树形DP即可,dfs后对每个节点更新收益最大值,单点的计算方法为:w=dp[i][0]+dp[i][1]
(由于前者是负的,相当于收入减去总花费)
#include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std; #define mst(a,b) memset((a),(b),sizeof(a)) #define rush() int T;scanf("%d",&T);while(T--) typedef long long ll; const int maxn = 100005; const ll mod = 1e9+7; const int INF = 0x3f3f3f3f; const double eps = 1e-6; struct node { int v,w; node(int _v,int _w):v(_v),w(_w) {} }; int n,ans; int val[maxn]; int dp[maxn][2]; vector<node>vec[maxn]; void dfs(int u,int pre) { dp[u][0]=-val[u]; dp[u][1]=val[u]; for(int i=0;i<vec[u].size();i++) { int v=vec[u][i].v; int w=vec[u][i].w; if(v==pre) continue; dfs(v,u); dp[u][0]=max(dp[u][0],dp[v][0]-w); dp[u][1]=max(dp[u][1],dp[v][1]-w); } ans=max(ans,dp[u][0]+dp[u][1]); } int main() { int u,v,w; rush() { scanf("%d",&n); for(int i=0;i<=n;i++) { vec[i].clear(); } for(int i=1;i<=n;i++) { scanf("%d",&val[i]); } for(int i=1;i<n;i++) { scanf("%d%d%d",&u,&v,&w); vec[u].push_back(node(v,w)); vec[v].push_back(node(u,w)); } ans=0; dfs(1,-1); printf("%d ",ans); } return 0; }
网络流:
直接构图 费用流跑一遍
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> #include<string.h> #include<set> #include<vector> #include<queue> #include<stack> #include<map> #include<cmath> typedef long long ll; typedef unsigned long long LL; using namespace std; const double PI=acos(-1.0); const double eps=0.0000000001; const int INF=0x3f3f3f3f; const int N=1000000+100; int a[N]; int head[N]; int dis[N]; int pre[N]; int vis[N]; int tot; int m,n; struct node{ int from,to,next,flow,cost; }edge[N<<1]; void init(){ memset(head,-1,sizeof(head)); tot=0; } void add(int u,int v,int c,int cost){ edge[tot].from=u; edge[tot].to=v; edge[tot].flow=c; edge[tot].cost=cost; edge[tot].next=head[u]; head[u]=tot++; edge[tot].from=v; edge[tot].to=u; edge[tot].flow=0; edge[tot].cost=-cost; edge[tot].next=head[v]; head[v]=tot++; } int spfa(int s,int t){ memset(pre,-1,sizeof(pre)); memset(dis,INF,sizeof(dis)); memset(vis,0,sizeof(vis)); queue<int>q; dis[s]=0; vis[s]=1; q.push(s); while(!q.empty()){ int x=q.front(); q.pop(); vis[x]=0; for(int i=head[x];i!=-1;i=edge[i].next){ int v=edge[i].to; if(edge[i].flow&&dis[v]>dis[x]+edge[i].cost){ dis[v]=edge[i].cost+dis[x]; pre[v]=i; if(vis[v]==0){ vis[v]=1; q.push(v); } } } } if(pre[t]==-1)return 0; return 1; } int MCMF(int s,int t){ int flow=0; int cost=0; while(spfa(s,t)){ int minn=INF; for(int i=pre[t];i!=-1;i=pre[edge[i].from]){ minn=min(minn,edge[i].flow); } for(int i=pre[t];i!=-1;i=pre[edge[i].from]){ edge[i].flow=edge[i].flow-minn; edge[i^1].flow=edge[i^1].flow+minn; cost=edge[i].cost+cost; // cout<<cost<<endl; } flow=flow+minn; } return cost; } int main(){ int tt; scanf("%d",&tt); while(tt--){ init(); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } int s=0; int s1=n+1; int t=n+2; add(s,s1,1,0); for(int i=1;i<=n;i++){ add(s1,i,1,-a[i]); } for(int i=1;i<=n;i++){ add(i,t,1,a[i]); } for(int i=1;i<=n-1;i++){ int u,v,cost; scanf("%d%d%d",&u,&v,&cost); add(u,v,1,cost); add(v,u,1,cost); } cout<<abs(MCMF(s,t))<<endl; } }