【CodeChef】Annual Parade -最小費用最大流&無向圖最小鏈覆蓋
阿新 • • 發佈:2018-11-26
傳送門:Annual Parade
題解
求鏈覆蓋所有點的最小花費,考慮拆點跑最小費用最大流。
次關於
的詢問說明費用流實際上和
的關係不大。
先考慮如何拋開
回答單次詢問。
考慮拆點:將
拆成
。
源點
->
連一條流量為
,費用為
的邊。
->匯點
連一條流量為
,費用為
的邊。
每條路徑
連一條
流量為
,費用為
的邊。
->
連一條流量為
,費用為
的邊(多次經過一個點)。
觀察每次一條新的增廣路(費用為 )的貢獻:連線了兩條不連通的路徑,使得原花費 ;連成了環,也使得原花費 。
初始化費用為 (沒有路徑),每一條新的增廣路的貢獻為 。那麼花費最小的方案就是選擇所有 的增廣路。
所以先 跑一遍任意兩點之間最短路,跑一遍最小費用最大流,依次記錄每條增廣路的花費。最後每次詢問二分回答即可。
程式碼
#include<bits/stdc++.h>
using namespace std;
const int N=510,M=4e5+10;
const int inf=0x3f3f3f3f;
int n,m,K,S,T,f[255][255],vs[N],tim,lim;
int head[N],cur[N],to[M],nxt[M],w[M],c[M],tot=1;
bool inq[N];int dis[N],prf,prc,flw[N],cst[N];
vector<int>dg;
inline void lk(int u,int v,int vv,int cc)
{
to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=vv;c[tot]=cc;
to[++tot]=u;nxt[tot]=head[v];head[v]=tot;w[tot]=0;c[tot]=-cc;
}
char cp,OS[100];
inline void rd(int &x)
{
cp=getchar();x=0;
for(;!isdigit(cp);cp=getchar());
for(;isdigit(cp);cp=getchar()) x=(x<<3)+(x<<1)+(cp^48);
}
inline void ot(int x)
{
int re=0;
for(;(!re)||(x);x/=10) OS[++re]='0'+x%10;
for(;re;--re) putchar(OS[re]);
putchar('\n');
}
deque<int>que;
inline bool spfa()
{
int i,j,x;
memset(dis,0x3f,lim);dis[T]=0;inq[T]=true;que.push_back(T);
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]-c[i])) continue;
dis[j]=dis[x]-c[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,int cot)
{
vs[x]=tim;
if(x==T){
dg.push_back(cot);
int sz=dg.size();
prf+=f;flw[sz]=prf;
prc+=f*cot;cst[sz]=prc;
return f;
}
int j,res,ss=0;
for(int &i=cur[x];i;i=nxt[i]){
j=to[i];if((!w[i])||(vs[j]==tim)||(dis[j]!=dis[x]-c[i])) continue;
res=dfs(j,min(f-ss,w[i]),cot+c[i]);if(!res) continue;
w[i]-=res;w[i^1]+=res;ss+=res;
if(ss==f) return ss;
}
if(!ss) dis[x]=-1;
return ss;
}
int main(){
int i,j,k,x,y,z;
memset(f,0x3f,sizeof(f));
rd(n);rd(m);rd(K);
for(i=1;i<=n;++i) f[i][i]=0;
for(i=1;i<=m;++i){
rd(x);rd(y);rd(z);
f[x][y]=min(f[x][y],z);
}
for(k=1;k<=n;++k)
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
S=(n<<1)+1;T=S+1;lim=sizeof(int)*(T+2);
for(i=1;i<=n;++i) lk(S,i,1,0),lk(i+n,T,1,0);
for(i=1;i<=n;++i)
for(j=1;j<=n;++j) if((i!=j)&&(f[i][j]<inf))
lk(i,j+n,1,f[i][j]);
for(;spfa();){
for(vs[T]=tim;vs[T]==tim;){
tim++;memcpy(cur,head,lim);dfs(S,inf,0);
}
}
for(;K;--K){
rd(z);x=lower_bound(dg.begin(),dg.end(),z)-dg.begin();
ot((n-flw[x])*z+cst[x]);
}
return 0;
}