「题解」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
求关注,求过。