dtoi2797 旅行商
Posted 1124828077ccj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了dtoi2797 旅行商相关的知识,希望对你有一定的参考价值。
题意:
camp国有n座城市,由1,2,...,n编号。城市由n–1条双向道路相连。任意两个城市之间存在唯一的道路连通。有m个旅行商,第i个旅行商会从城市ai旅行到城市bi,贩卖ci件商品。已知第i个城市的居民最多购买wi件商品,bobo想知道旅行商们能够卖出商品数量的最大值。
n,m<=20000。
题解:
考虑暴力,对于每一个旅行商,将其路径上的所有点都连边,然后跑最大流就可以了。不过边数太多了,会TLE。
那么这没有什么关系,我们可以树剖+线段树,将每个旅行商连向他们所对应的节点,容量为INF即可。当然每个线段树节点也都要向各自的城市连边。
这样的话,边数就优化成了m*logn*logn,再跑最大流,可以通过这道题。
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<vector> #include<queue> using namespace std; const int INF=2e9; typedef struct{ int w,zjds,xzd,dep,dfn,twz; }P; P p[20002]; int n,m,fa[22][20002],d[100005],cur[100005],cnt,hh=80000,s=100001,t=100002,df[20002]; vector<int>g[20002]; struct Edge{ int from,to,cap,flow; Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){} }; vector<int>c[100005]; vector<Edge>edges; void add(int u,int v,int w){ edges.push_back(Edge(u,v,w,0)); edges.push_back(Edge(v,u,0,0)); c[u].push_back(edges.size()-2); c[v].push_back(edges.size()-1); } bool bfs(int s){ queue<int>q;memset(d,-1,sizeof(d)); q.push(s);d[s]=0; while(!q.empty()) { int u=q.front();q.pop(); for (int i=0;i<c[u].size();i++) { Edge e=edges[c[u][i]]; if (e.cap>e.flow && d[e.to]==-1) { q.push(e.to);d[e.to]=d[u]+1; if (e.to==t)return true; } } } return false; } int dfs(int x,int a){ if (x==t)return a; int flow=0,f; for (int& i=cur[x];i<c[x].size();i++) { Edge& e=edges[c[x][i]]; if (e.cap>e.flow && d[x]+1==d[e.to] && (f=dfs(e.to,min(a,e.cap-e.flow)))>0) { flow+=f;a-=f; e.flow+=f;edges[c[x][i]^1].flow-=f; } if (!a)break; } return flow; } void dfs1(int x,int faa,int deep){ int Max=0,maxn=-1;p[x].zjds=1;fa[0][x]=faa;p[x].dep=deep; for (int i=0;i<g[x].size();i++) if (g[x][i]!=faa) { dfs1(g[x][i],x,deep+1);p[x].zjds+=p[g[x][i]].zjds; if (p[g[x][i]].zjds>Max) { Max=p[g[x][i]].zjds;maxn=g[x][i]; } } p[x].xzd=maxn; } void dfs2(int x,int fa){ p[x].dfn=++cnt;if (p[fa].xzd==x)p[x].twz=p[fa].twz;else p[x].twz=x; df[cnt]=x; if (p[x].xzd!=-1)dfs2(p[x].xzd,x); for (int i=0;i<g[x].size();i++) if (g[x][i]!=fa && g[x][i]!=p[x].xzd)dfs2(g[x][i],x); } int lca(int x,int y){ if (p[x].dep<p[y].dep)swap(x,y); int k=p[x].dep-p[y].dep; for (int i=0;i<=20;i++) if (k&(1<<i))x=fa[i][x]; if (x==y)return x; for (int i=20;i>=0;i--) if (fa[i][x]!=fa[i][y]) { x=fa[i][x];y=fa[i][y]; } return fa[0][x]; } void build(int root,int begin,int end){ if (begin==end) { add(s,root,p[df[begin]].w);return; } int mid=(begin+end)/2; build(root*2,begin,mid);build(root*2+1,mid+1,end); add(root*2,root,INF);add(root*2+1,root,INF); } void gengxin(int root,int begin,int end,int begin2,int end2,int wz){ if (begin>end2 || end<begin2)return; if (begin>=begin2 && end<=end2) { add(root,hh+wz,INF);return; } int mid=(begin+end)/2; gengxin(root*2,begin,mid,begin2,end2,wz);gengxin(root*2+1,mid+1,end,begin2,end2,wz); } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++)scanf("%d",&p[i].w); for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y);g[x].push_back(y);g[y].push_back(x); } dfs1(1,0,1);dfs2(1,0); for (int i=1;i<=20;i++) for (int j=1;j<=n;j++) fa[i][j]=fa[i-1][fa[i-1][j]]; build(1,1,n); for (int i=1;i<=m;i++) { int u,v,lc,h; scanf("%d%d%d",&u,&v,&h); lc=lca(u,v); while(p[u].dep>=p[lc].dep) { if (p[p[u].twz].dep<p[lc].dep)gengxin(1,1,n,p[lc].dfn,p[u].dfn,i); else { gengxin(1,1,n,p[p[u].twz].dfn,p[u].dfn,i); } u=fa[0][p[u].twz]; } while(p[v].dep>=p[lc].dep) { if (p[p[v].twz].dep<p[lc].dep)gengxin(1,1,n,p[lc].dfn,p[v].dfn,i); else { gengxin(1,1,n,p[p[v].twz].dfn,p[v].dfn,i); } v=fa[0][p[v].twz]; } add(hh+i,t,h); } int ans=0; while(bfs(s)){memset(cur,0,sizeof(cur));ans+=dfs(s,INF);} printf("%d ",ans); return 0; }
以上是关于dtoi2797 旅行商的主要内容,如果未能解决你的问题,请参考以下文章
TSP基于matlab蚁群算法求解旅行商问题含Matlab源码 1583期