Gym-101242B:Branch Assignment(最短路,四边形不等式优化DP)
题意:要完成一个由s个子项目组成的项目,给b(b>=s)个部门分配,从而把b个部门分成s个组。分组完成后,每一组的任
意两个点之间都要传递信息。假设在(i,j)两个点间传送信息,要先把信息加密,然后快递员从i出发到总部,再加
密,在到j点。出于安全原因,每次只能携带一条消息。现在给出了道路网络、各个部门和总部的位置,请输出快
递员要走的最小总距离。
思路:求最短路dis,排序。 由排序不等式,dis相近的分到一组。 那么就是一个分组问题,可以用四边形不等式; 决策单调性DP; 二分+单调栈; 斜率优化。
#include<bits/stdc++.h> #define s second #define f first #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int inf=1e9; const int maxn=100010; int Laxt[maxn],Next[maxn],To[maxn],Len[maxn],cnt; int a[maxn],b[maxn],c[maxn],dis[maxn],N,M,S,B,s[5010][5010]; ll dp[5010][5010],sum[5010]; pair<int,int>p[maxn]; int vis[maxn]; void read(int &x){ x=0; char c=getchar(); while(c>'9'||c<'0') c=getchar(); while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); } void add(int u,int v,int l) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=l; } struct in{ int dis,u; in(){} in(int dd,int uu):dis(dd),u(uu){} friend bool operator <(in w,in v){ return w.dis>v.dis; } }; void SPFA() { rep(i,1,M) swap(a[i],b[i]); cnt=0; rep(i,1,N) Laxt[i]=0,vis[i]=0,dis[i]=inf; rep(i,1,M) add(a[i],b[i],c[i]); priority_queue<in>q; q.push(in(0,B+1)); dis[B+1]=0; while(!q.empty()){ int u=q.top().u; q.pop(); vis[u]=0; for(int i=Laxt[u];i;i=Next[i]){ int v=To[i];if(dis[v]>dis[u]+Len[i]){ dis[v]=dis[u]+Len[i]; if(!vis[v]) vis[v]=1,q.push(in(dis[v],v)); } } } } int main() { while(~scanf("%d%d%d%d",&N,&B,&S,&M)){ rep(i,1,M) read(a[i]),read(b[i]),read(c[i]); SPFA(); rep(i,1,B) p[i].s=i,p[i].f=dis[i]; SPFA(); rep(i,1,B) p[i].f+=dis[i]; sort(p+1,p+B+1); rep(i,1,B) sum[i]=sum[i-1]+p[i].f; memset(s,0,sizeof(s)); memset(dp,0x3f,sizeof(dp)); dp[0][0]=0; rep(k,0,S) s[B+1][k]=B; rep(k,1,S){ for(int i=B;i>=1;i--) { for(int j=s[i][k-1];j<=s[i+1][k]&&j<i;j++){ if(dp[i][k]>dp[j][k-1]+1LL*(i-j-1)*(sum[i]-sum[j])){ dp[i][k]=dp[j][k-1]+1LL*(i-j-1)*(sum[i]-sum[j]); s[i][k]=j; } } } } printf("%lld\n",dp[B][S]); } return 0; }
It is your time to fight!