「题解」CF1187G Gang Up

【题解】CF1187G Gang Up

题意

给定一个图,有 \(k\) 个人要走到 \(1\) 号节点,问最小花费。

解法

一眼丁真,鉴定为费用流。

考虑到这道题花费会与时间有关,所以 分层图,启动!

按时刻分层,现在分析每个人在第 \(k\) 时刻的动向:

1. 呆着不动。
2. 走到下一个节点。

对于动向 \(1\) ,从时刻 \(k\) 连向 时刻 \(k+1\) ,流量 \(inf\) ,费用 \(0\) 的边。

对于动向 \(2\) ,由于代价 \(a^2\) 有关,所以不能直接建边。

我们分析一下每增加一个人会增加多少费用,也就是考虑怎么把这个平方拆开,直接上公式 \(n^2=\sum\limits_{i=1}^n{2\times i-1}\)

把每一条原图中的边拆为 \(k\) 条边,对于第 \(i\) 条边,建一条 容量为 \(1\),费用为 \(d\times(2\times-1)\) 的边。

其他边就很好建了,不多赘述 (直接看代码吧)。

代码

注意数组不要开小了。

#include<bits/stdc++.h>
using namespace std;//不过是水题罢了 
const int MX_N=50100,MX_M=5010000,INF=0x3f3f3f3f;
const int tim=120;
struct node{
    int next,to;
    int w,c;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w,int c){
    node &i=edge[edge_cnt];
    i.next=head[x],i.w=w,i.c=c,i.to=y;
    head[x]=edge_cnt++;
}
inline void add(int x,int y,int w,int c){
    Add(x,y,w,c),Add(y,x,0,-c);
}
int s=0,t=MX_N-1;
int dist[MX_N]={0},pre[MX_N]={0},lim[MX_N]={0};
bool vis[MX_N]={0};
bool spfa(){
    for(int i=0;i<MX_N;i++)  dist[i]=INF,lim[i]=vis[i]=0;
    queue<int > qu;qu.push(s);vis[s]=1,dist[s]=0,lim[s]=INF;
    while(!qu.empty()){
        int now=qu.front();qu.pop();vis[now]=0;
        for(int i=head[now];~i;i=edge[i].next){
            int to=edge[i].to,w=edge[i].w,c=edge[i].c;
            if(dist[to]>dist[now]+c&&w){
                dist[to]=dist[now]+c;
                pre[to]=i;
                lim[to]=min(lim[now],w);
                if(!vis[to]){
                    qu.push(to);
                    vis[to]=1;
                }
            }
        }
    }
    return lim[t]>0;
}
void EK(int &flow,int &cost){
    flow=cost=0;
    while(spfa()){
        flow+=lim[t];
        cost+=lim[t]*dist[t];
        for(int i=t;i!=s;i=edge[pre[i]^1].to){
            edge[pre[i]].w-=lim[t];
            edge[pre[i]^1].w+=lim[t];
        }
    }
}
int n,m,k,c,d;
inline int has(int now,int ti){
    return ti*n+now;
}
signed main(){
    memset(head,-1,sizeof(head));
    //=======================================
    scanf("%d%d%d%d%d",&n,&m,&k,&c,&d);
    for(int i=1;i<=k;i++){
        int ai;scanf("%d",&ai);
        add(s,has(ai,0),1,0);
    }
    for(int i=1;i<=m;i++){
        int u,v;scanf("%d%d",&u,&v);
        for(int j=0;j<=tim;j++){
            for(int x=1;x<=k;x++){
                add(has(u,j),has(v,j+1),1,d*(x*2-1));
                add(has(v,j),has(u,j+1),1,d*(x*2-1));
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=tim;j++){
            add(has(i,j-1),has(i,j),INF,0);
        }
    }
    for(int j=0;j<=tim;j++)  add(has(1,j),t,INF,c*j);
    int flow,cost;EK(flow,cost);
    printf("%d",cost);
    //=======================================
    return 0;
}//CF1187G

求关注,求过。

posted @ 2024-04-11 09:46  是菜菜呀  阅读(16)  评论(0编辑  收藏  举报