• 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
    ",dp[B][S]);
        }
        return 0;
    }
     
  • 相关阅读:
    页面上有10个多选框,实现三个按钮(重置、反选、全选)功能
    鼠标点哪 哪出15*15的圆型div
    es写简单的留言板
    面试准备(3)事件循环
    面试准备(2)async+await的使用与原理
    面试准备(1)重排与重绘和验证码
    vue项目修改el-input样式
    echarts画雷达图详解
    决心
    国庆中秋
  • 原文地址:https://www.cnblogs.com/hua-dong/p/11278117.html
Copyright © 2020-2023  润新知