【BZOJ】2324: [ZJOI2011]營救皮卡丘-MCMF
阿新 • • 發佈:2018-11-26
傳送門:bzoj2324
題解
首先 處理出每個點對 在不經過任何標號大於 的點時的最短路 ,便求出了一個點到另一個點的花費。
摧毀一個點是一次性的,所以將問題轉換為將 分成 組遞增數列 ,滿足 最小。類似於 的最小路徑覆蓋。
考慮拆點(入度 出度 )構圖,滿足 號點出度為 , 號點出入度均為1, 號點入度為1,時的MCMF。
號點的向匯點連一條流量為 ,費用為 的邊。(入度)
源點向 連一條流量為 ,費用為 的邊,向 分別連一條流量為 ,費用為 的邊。(出度)
每個點對 ,從 向 連一條流量為 ,費用為 的邊。
跑 的花費即為答案。
p.s. 因為出度比較好限制所以和源點連,入度只能拿來判斷所以和匯點連。
程式碼
#include<bits/stdc++.h>
using namespace std;
const int N=400,M=1e6+10,inf=0x3f3f3f3f;
typedef long long ll;
int n,m,K,S,T,d[160][160],vs[N],dis[N],tim;
int cur[N],head[N],to[M],nxt[M],w[M],cc[M],tot=1;
ll tot_cost;bool inq[N];
inline void lk(int u,int v,int flw,int cst)
{
to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=flw;cc[tot]=cst;
to[++tot]=u;nxt[tot]=head[v];head[v]=tot;w[tot]=0;cc[tot]=-cst;
}
inline void dn(int &x,int y){if(y<x) x=y;}
deque<int>que;
inline bool spfa()
{
memset(dis,0x3f,sizeof(dis));
int i,j,x;
dis[T]=0;que.push_back(T);inq[T]=true;
for(;que.size();){
x=que.front();que.pop_front();
for(i=head[x];i;i=nxt[i]){
j=to[i];if((!w[i^1])||(dis[j]<=dis[x]-cc[i])) continue;
dis[j]=dis[x]-cc[i];if(inq[j]) continue;
if(que.empty()||(dis[j]<=dis[que.front()])) que.push_front(j);
else que.push_back(j);inq[j]=true;
}
inq[x]=false;
}
return dis[S]<inf;
}
int dfs(int x,int f)
{
vs[x]=tim;
if(x==T) return f;
int j,res,ss=0;
for(int &i=cur[x];i;i=nxt[i]){
j=to[i];if((!w[i])||(dis[j]!=dis[x]-cc[i])||(vs[j]==tim)) continue;
res=dfs(j,min(w[i],f-ss));if(!res) continue;
w[i]-=res;w[i^1]+=res;tot_cost+=(ll)cc[i]*res;
ss+=res;if(ss==f) return ss;
}
if(!ss) dis[x]=-1;
return ss;
}
int main(){
memset(d,0x3f,sizeof(d));
int i,j,k,x,y,z;
scanf("%d%d%d",&n,&m,&K);n++;
S=(n<<1)+1;T=S+1;
for(i=1;i<=n;++i) d[i][i]=0;
for(i=1;i<=m;++i){
scanf("%d%d%d",&x,&y,&z);
x++;y++;
dn(d[x][y],z);dn(d[y][x],z);
}
for(k=1;k<=n;++k)
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
if((k<=i||k<=j))
dn(d[i][j],d[i][k]+d[k][j]);
lk(S,1+n,K,0);
for(i=2;i<=n;++i) lk(S,i+n,1,0),lk(i,T,1,0);
for(i=1;i<n;++i)
for(j=i+1;j<=n;++j)
if(d[i][j]<inf)
lk(i+n,j,1,d[i][j]);
for(;spfa();)
for(vs[T]=tim;vs[T]==tim;){
memcpy(cur,head,sizeof(cur));
++tim;dfs(S,inf);
}
printf("%lld",tot_cost);
return 0;
}