Live2d Test Env

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;
}

 

 
posted @ 2019-07-31 18:05  nimphy  阅读(386)  评论(0编辑  收藏  举报